Author

Topic: Preventing the exposure of public addresses on a website (Read 1172 times)

full member
Activity: 129
Merit: 100
I think the right way to whitelist an ip is to put something like this in your bitcoin.conf file:

Code:
rpcallowip=yourwebserverip

I didn't do this. I instead wrote some ocaml code that could on the one hand locally ask bitcoind questions and on the other hand handle simple (but obscure) Q&A via a socket. I don't recommend doing it like I did, but I have trouble getting bitcoind to do what I want.

I'll put some mysql and php here in case it helps you or anyone else who comes across this thread later. In the process of cleaning and documenting these clips of code, I may have introduced errors, but it should give the idea. Also, I'm not giving the full environment (e.g., connecting to mysql from php).

Use at your own risk, and all other such caveats.

This code was for making bitcoin payments to activate an access code in order to obtain access to an online document.

Here is the relevant mysql table. I had a collection of (bitcoin-address,access-code) pairs for each document.
Code:
CREATE TABLE IF NOT EXISTS `docaccesscode` (
  `docaccesscodeid` mediumint(9) NOT NULL AUTO_INCREMENT,
  `docsha` char(64) NOT NULL,
-- price (in satoshis)
  `docaccesscodeprice` BIGINT(19),
-- bitcoin address
  `docaccesscodeaddr` varchar(34),
-- "access code"
  `docaccesscode` varchar(21),
-- hash of access code
  `docaccesscodehash` char(64) NOT NULL UNIQUE,
-- has this access code/payment address already been used? If so, put the timestamp. If not, it is NULL
  `docaccesscodeused` int(11) DEFAULT NULL,
-- has the payment been made?
  `docaccesscodeactive` bool NOT NULL DEFAULT false,
  PRIMARY KEY (`docaccesscodeid`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=0 ;

Here is php code to request an access code and an address to pay to activate the access code.
Code:
// A helper function to write the number of satoshis in a nice way as "bitcoins, mbits or satoshis"
function satoshivalstr ($s) {
  if ($s > 100000000) {
    return (($s / 100000000)." bitcoins");
  } else if ($s == 100000000) {
    return "1 bitcoin";
  } else if ($s > 100000) {
    return (($s / 100000)." mbits (i.e., ".($s / 100000000)." bitcoins)");
  } else if ($s == 100000) {
    return "1 mbit (i.e., 0.001 bitcoins)";
  } else {
    return ($s." satoshis (i.e., ".($s / 100000000)." bitcoins)");
  }
}

$tm = time();
// grab an unused address/access code
$newcodel = mysql_query("select docaccesscodeid,docaccesscodeprice,docaccesscodeaddr,docaccesscode from `docaccesscode` where docaccesscodeused
 IS NULL and docaccesscodecurr=0 and docsha='".$_REQUEST['d']."' ORDER BY RAND() LIMIT 1");
// set it as used (and record when it was "exposed")
mysql_query("update `docaccesscode` SET docaccesscodeused=".$tm." WHERE docaccesscodeid=".$newcode['docaccesscodeid']);
// Say "here is your access code and please pay this address"
echo 'Access code: '.$newcode['docaccesscode'].'
Pay '.satoshivalstr($newcode['docaccesscodeprice']).' to the address '.$newcode['docaccesscodeaddr'].' to ac\
tivate the access code.
';

Clip of php code for checking if a payment has been made (activating an access code).  This first asks the mysql database. If it says it's active, the document is presented.  If it says it's not yet active (payment has not yet been made), then a function cs() initalizes a socket connecting to my "payment processor server".  I send "P".$ach through this socket to indicate that I want to know if the payment for the access code with hash $ach has been received. The payment processor server knows which bitcoin address this corresponds to (so I'm not sending the address itself).  The payment processor server (some ocaml code) asks bitcoind about the right address and either responds with the character 'P' for "Paid" or something else.  If the socket says its been paid, then the mysql database is updated accordingly and the document is presented.

Code:
if ($_REQUEST['accesscode']) {
  $ach = hash('ripemd160',$_REQUEST['accesscode']);
  $docaccessl = mysql_query("select docaccesscodeactive from `docaccesscode` where docsha='".$_REQUEST['d']."' AND docaccesscodehash='".$ach."'");
  if ($docaccess = mysql_fetch_array($docaccessl)) {
    if ($docaccess['docaccesscodeactive']) {
      presentdoc($doc);
    } else {
      if ($sock = cs()) {
         socket_write($sock,"P".$ach,41);
         $o = socket_read($sock,1);
         if ($o == 'P') {
            mysql_query("update `docaccesscode` set docaccesscodeactive=1 where docsha='".$_REQUEST['d']."' AND docaccesscodehash='".$ach."'");
            presentdoc($doc);
          } else {
            echo 'Access to this document is currently restricted. Your access will be granted after your payment has been received and processed.';
          }
       } else {
         echo 'The payment processor server appears to be down.';
       }
    }
  }
} else {
  echo 'You need an active access code to see the document.'
}
newbie
Activity: 23
Merit: 0
with point 2&5 many people use their own home computers or another remote server, that does the checking and then sends a 'payment sent' to the database on customer facing website server. plus updating the customer facing website database with fresh public keys, making the home/remote server the brains of the operation and the customer facing webserver. just a GUI input viewer
hmm, ok, so i setup a rasberry pi with bitcoind and it just sits there and polls my public webserver from a private ip. er? ok guys,  i'm brain farting on this whitelisting/polling/bitcoind part, which i have never used before.
newbie
Activity: 23
Merit: 0
1. ....do it (offline!) using bitaddress.org (see the "bulk" option).
+++++ will do.

2. Put the addresses (not the private keys) into a database on your web server. There should also be a column indicating whether or not the address has already been used. You probably also want a column indicating whether the payment has been received. I had a mysql table for all of this.
+++++ ok, i'll put the public addresses into a mongodb and add a couple fields for used and paid etc, maybe even a notes field, timestamp, etc.

3. Each time someone orders something, randomly choose an unused address. This can be done with some basic php/mysql interaction.
+++++ i'll do it in nodejs. i love your random idea here too!

4. Mark the address as used and display it to the buyer. This should be done over https so that it is not visible to third parties. This is the only time the address will be sent from you to the buyer.
+++++ yep, @franky1 is on to something there with the "" idea. how do we quickly show the qr and hopefully the "textual" address to the customer in a way that can't get snagged by google? there must be a form post first, which sends request to node or meteor or something, then that server side code generates the image server side with a random filename which then shows that image to the customer in a compiled file format such as jpeg or gif. a simple math problem instead of captchas would keep the bots out i think. hmmmf

5. Here's the final and most problematic step. You should check for when the payment is made (with n>=0 confirmations) and mark it as paid in the database at that point. Here's how *not* to do it: Call a third party site like blockchain.info. If you call a third party, then you've leaked the address. You chould have bitcoind running on your server, but to watch an address you have to have the private key in the wallet. It's a terrible idea to have wallets with private keys on a web server (which is a real shame). You can encrypt the wallet with an extremely high entropy password and it's probably safe, but I wouldn't recommend it. I'll tell you what I did: I rented a separate server that only ran bitcoind (no apache), put the wallet in question with a very high entropy password on that server. I whitelisted that my webserver could ask about payments to certain addresses. (Well, what I did was a little more complicated, but I'm trying to give the idea.) You could also secretly just wait half an hour and then assume the payment was made. The buyer will probably assume you are waiting for confirmations. That's the technically easiest solution. Smiley
+++++ as bitaddress states on their bulk wallet page, the "bitcoin payment notification service" will be tough too since you are querying over the wire a specific address, essentially broadcasting that it's yours. i'd like to avoid bitcoind. a web service or blockchain style decentralized email address might just be the way to get automated notifications. this has got to be DUMB. a lot of my customers are mom and pop shop folks who know nothing about tech. but, if they know that they have to wait until they get the "notification" in some way, then they won't ship anything out till they know for sure it was paid for. this is a tough one indeed... hmmmf

PS: I just saw your latest reply. I like money.
full member
Activity: 129
Merit: 100
I like franky1's suggestion. The "other" computer could handle more than just checking for payments. On the other hand, sometimes the "other" computer might be temporarily unavailable. In that case, it's useful to still be able to give out a payment address immediately.

PS: I just saw your latest reply. I like money.

While I do like money, the truth is that what I'm describing is simple enough that I wouldn't charge anything for sharing it. Also, the things I never did (dealing with images/QR codes) I'm not very interested in doing at the moment. I'll see if I can isolate a few lines of mysql and php that anyone can copy to start from. If I can, then I'll post it here.
legendary
Activity: 4410
Merit: 4788
I've done what you're describing and I can tell you how I did it.

2. Put the addresses (not the private keys) into a database on your web server. There should also be a column indicating whether or not the address has already been used. You probably also want a column indicating whether the payment has been received. I had a mysql table for all of this.

5. Here's the final and most problematic step. You should check for when the payment is made (with n>=0 confirmations) and mark it as paid in the database at that point. Here's how *not* to do it: Call a third party site like blockchain.info. If you call a third party, then you've leaked the address. You chould have bitcoind running on your server, but to watch an address you have to have the private key in the wallet. It's a terrible idea to have wallets with private keys on a web server (which is a real shame). You can encrypt the wallet with an extremely high entropy password and it's probably safe, but I wouldn't recommend it. I'll tell you what I did: I rented a separate server that only ran bitcoind (no apache), put the wallet in question with a very high entropy password on that server. I whitelisted that my webserver could ask about payments to certain addresses. (Well, what I did was a little more complicated, but I'm trying to give the idea.) You could also secretly just wait half an hour and then assume the payment was made. The buyer will probably assume you are waiting for confirmations. That's the technically easiest solution. Smiley

PS: I just saw your latest reply. I like money.

with point 2&5 many people use their own home computers or another remote server, that does the checking and then sends a 'payment sent' to the database on customer facing website server. plus updating the customer facing website database with fresh public keys, making the home/remote server the brains of the operation and the customer facing webserver. just a GUI input viewer
legendary
Activity: 4410
Merit: 4788
I'd suggest that you look into "stealth addresses" and what APIs people are providing to help with that.

yep, here (http://bitcoin.stackexchange.com/questions/20701/what-is-a-stealth-address) and Peter Todd on SourceForge mention it, but it is very alpha stage yet.
 
so, nobody really knows how to do what i want yet?
anybody wanna make some money..?

using QR codes are better then text based addresses, and there are already QR code making code available so that your website would only show "" instead of ""

as for doing bitcoin exchanges anonymously without google indexing addresses, irc: bitcoin-otc and localbitcoins does this as all deposit addresses are not available on public viewable webpages
full member
Activity: 129
Merit: 100
I've done what you're describing and I can tell you how I did it.

1. Generate a lot of addresses and private keys. I did this with my own bip0032 implementation, but you can also do it (offline!) using bitaddress.org (see the "bulk" option). Make sure not to lose the private keys, of course.

2. Put the addresses (not the private keys) into a database on your web server. There should also be a column indicating whether or not the address has already been used. You probably also want a column indicating whether the payment has been received. I had a mysql table for all of this.

3. Each time someone orders something, randomly choose an unused address. This can be done with some basic php/mysql interaction.

4. Mark the address as used and display it to the buyer. This should be done over https so that it is not visible to third parties. This is the only time the address will be sent from you to the buyer.

5. Here's the final and most problematic step. You should check for when the payment is made (with n>=0 confirmations) and mark it as paid in the database at that point. Here's how *not* to do it: Call a third party site like blockchain.info. If you call a third party, then you've leaked the address. You chould have bitcoind running on your server, but to watch an address you have to have the private key in the wallet. It's a terrible idea to have wallets with private keys on a web server (which is a real shame). You can encrypt the wallet with an extremely high entropy password and it's probably safe, but I wouldn't recommend it. I'll tell you what I did: I rented a separate server that only ran bitcoind (no apache), put the wallet in question with a very high entropy password on that server. I whitelisted that my webserver could ask about payments to certain addresses. (Well, what I did was a little more complicated, but I'm trying to give the idea.) You could also secretly just wait half an hour and then assume the payment was made. The buyer will probably assume you are waiting for confirmations. That's the technically easiest solution. Smiley

PS: I just saw your latest reply. I like money.
newbie
Activity: 23
Merit: 0
I'd suggest that you look into "stealth addresses" and what APIs people are providing to help with that.

yep, here (http://bitcoin.stackexchange.com/questions/20701/what-is-a-stealth-address) and Peter Todd on SourceForge mention it, but it is very alpha stage yet.
 
so, nobody really knows how to do what i want yet?
anybody wanna make some money..?
legendary
Activity: 1890
Merit: 1086
Ian Knowles - CIYAM Lead Developer
I'd suggest that you look into "stealth addresses" and what APIs people are providing to help with that.
newbie
Activity: 23
Merit: 0
You want to be looking into Stealth Addresses (that way you can publish a public key but nothing can be traced to it).

so nobody has written an api for everything i'm asking for yet? am i just being overly anal about anonymity, or? there has got to be a js lib for this...
legendary
Activity: 1890
Merit: 1086
Ian Knowles - CIYAM Lead Developer
You want to be looking into Stealth Addresses (that way you can publish a public key but nothing can be traced to it).
newbie
Activity: 23
Merit: 0
My Clients are demanding more anonymity and security in their web apps, those that use btc and ltc, etc. They are not comfortable with Exchanges and central points of possible failure.

Let's ANONYMOUSLY offer btc and ltc payments on our websites without the use of an Exchange.

Using npm/bitcoinjs or another pkg I want to ONLY show the ROTATING key and qr code once, and only if the website user requests it through a form submit or something.

This way, google and the like will never have a chance to index one of your public keys, not even once. Hence, no domain owner <> public keys can ever be indexed/referenced.

Maybe I could get the wallet to pre-generate say, 10,000 public multisig public keys and store them in a mongodb or something, then privately "show" them on screen somehow (no clear text, high rez gif or jpg? (svg is crawlable)) for only 60 seconds when they are requested by a customer who wants to pay my Client on their website.

Is this even possible yet? If so, is there a nodejs pkg or other javascript api that can be used to accomplish this, even remotely?
Jump to: