Difference between revisions of "Talk:HTTP Post request to a PHP server"

From Second Life Wiki
Jump to navigation Jump to search
Line 12: Line 12:
--[[User:Nite Zelmanov|Nite Zelmanov]] 20:37, 27 September 2007 (PDT)
--[[User:Nite Zelmanov|Nite Zelmanov]] 20:37, 27 September 2007 (PDT)


For general paranoia purposes you should use the nonce and a prefixed string; waste not, want not. It is my belief that the secret shouldn't be a string or an integer but an algorithm. A black box that can be fed a secret & the day/time and spit out a reproducible response. You then use the result of that alg as your secret for your hash. When someone cracks the secret used to hash a single message it won't be the same secret used on other messages, or at least not many; hopefully by the time they have cracked the temporal secret it will have expired. An attacker would have to brute force multiple temporal secrets to even start trying to figure out how the black box worked. By combining time with your secret in a non-obvious way you can protect your secret from direct brute forcing. There are other ways... If you know every message is going to be received, you can increment your secret (as a result of passing it through the black box).  You want to prefix your (temporary) secret and not postfix it to the data you are hashing. MD5 uses 64 byte blocks, you build the final hash one block at a time. If the secret is postfixed the cracker can cache the temporary value up to the last complete block; in effect they only have to brute force the hash on one block instead of the complete message. By prefixing the secret the caching optimization can't be used. -- [[User:Strife Onizuka|Strife Onizuka]] 22:03, 27 September 2007 (PDT)
For general paranoia purposes you should use the nonce and a prefixed string; waste not, want not. Regardless how you affix the secret, it is my belief that the secret shouldn't be a string or an integer but an algorithm. A black box that can be fed a secret & the day/time and spit out a reproducible response. You then use the result of that alg as your secret for your hash. When someone cracks the secret used to hash a single message it won't be the same secret used on other messages, or at least not many; hopefully by the time they have cracked the temporal secret it will have expired. An attacker would have to brute force multiple temporal secrets to even start trying to figure out how the black box worked. By combining time with your secret in a non-obvious way you can protect your secret from direct brute forcing. There are other ways... If you know every message is going to be received, you can increment your secret (as a result of passing it through the black box).  You want to prefix your (temporary) secret and not postfix it to the data you are hashing. MD5 uses 64 byte blocks, you build the final hash one block at a time. If the secret is postfixed the cracker can cache the temporary value up to the last complete block; in effect they only have to brute force the hash on one block instead of the complete message. By prefixing the secret the caching optimization can't be used. -- [[User:Strife Onizuka|Strife Onizuka]] 22:03, 27 September 2007 (PDT)


A simple black box:
A simple black box:
<pre>
<pre>
//I prefer an MD5 because it shakes up the bits.
string BlackBox(string secret, integer nonce)//changes every minute
string BlackBox(string secret, integer nonce)//changes every minute
{
{
     return llMD5String(llGetSubString(llGetTimestamp(),0,15) + secret, nonce);
     return llMD5String(llGetSubString(llGetTimestamp(),0,15) + secret, nonce);
}
string Hash(string data, string secret, integer nonce)
{
    return llMD5String(llMD5String(llGetSubString(llGetTimestamp(),0,15) + secret, nonce ^ 0x7e9b23f1) + data, nonce);
}
string Hash2(string data, string secret, integer nonce, integer offset)
{//for the main hash, the nonce is a moving target.
//In essence this function allows for the use of 3 secrets: secret, nonce and offset.
    return llMD5String(data, (integer)("0x" + llGetSubString(llMD5String(llGetSubString(llGetTimestamp(),0,15) + secret, nonce),offset,(offset + 7)%32)));
}
}
</pre>
</pre>

Revision as of 22:21, 27 September 2007


Is it possible to provide known input values and intercept the hash as it is passed to the web server thereby determining the secret key? Is providing the hash as part of the URL the best strategy? User:Hackshaven Harford

Transmitting the hash is perfectly safe however the method for calculating the hash will lead to the eventual brute forcing of SECRET_NUMBER. Since this script is open source and only uses a 32bit secret, an attack only needs to intercept one message. At the point in the PHP script where the hash is checked the attacker would systematically try every single MD5 nonce, until one of them worked. A year or so ago I was doing some consulting for a guy who was developing a similar system. Using an open source MD5 implementation written in C that I tweaked, I was able to try every nonce in less then 24 hours on a 600MHz Pentium 3. Imagine how fast it would run if it were multi-threaded on a modern multi-core system, now imagine a small cluster of modern computers. If you don't mind it taking several months you can also do this in LSL. If you want to make sure you don't get communication injections don't use this script. -- Strife Onizuka 09:17, 25 April 2007 (PDT)

Strife makes a great point, 32bits is not enough. Strife, I'd like to know what you think is the correct way given the tools we've got. In the meantime, I think you can afford a significant amount of extra protection by using a longer passphrase in place of the 32bit nonce.

string XREQUEST_PASSPHRASE = "nVBh)cCBy7l6ieihewF3Y__QZZ";
string hash=llMD5String(body + XREQUEST_PASSPHRASE,0);

If you make some guesstimates about how long (z) it takes to brute force (x) bits on a cluster of cost (y), you can then measure your paranoia precisely and create a passphrase to suit. Any objections to this implementation? It's still not great, but what else have we got? --Nite Zelmanov 20:37, 27 September 2007 (PDT)

For general paranoia purposes you should use the nonce and a prefixed string; waste not, want not. Regardless how you affix the secret, it is my belief that the secret shouldn't be a string or an integer but an algorithm. A black box that can be fed a secret & the day/time and spit out a reproducible response. You then use the result of that alg as your secret for your hash. When someone cracks the secret used to hash a single message it won't be the same secret used on other messages, or at least not many; hopefully by the time they have cracked the temporal secret it will have expired. An attacker would have to brute force multiple temporal secrets to even start trying to figure out how the black box worked. By combining time with your secret in a non-obvious way you can protect your secret from direct brute forcing. There are other ways... If you know every message is going to be received, you can increment your secret (as a result of passing it through the black box). You want to prefix your (temporary) secret and not postfix it to the data you are hashing. MD5 uses 64 byte blocks, you build the final hash one block at a time. If the secret is postfixed the cracker can cache the temporary value up to the last complete block; in effect they only have to brute force the hash on one block instead of the complete message. By prefixing the secret the caching optimization can't be used. -- Strife Onizuka 22:03, 27 September 2007 (PDT)

A simple black box:

//I prefer an MD5 because it shakes up the bits.
string BlackBox(string secret, integer nonce)//changes every minute
{
    return llMD5String(llGetSubString(llGetTimestamp(),0,15) + secret, nonce);
}

string Hash(string data, string secret, integer nonce)
{
    return llMD5String(llMD5String(llGetSubString(llGetTimestamp(),0,15) + secret, nonce ^ 0x7e9b23f1) + data, nonce);
}

string Hash2(string data, string secret, integer nonce, integer offset)
{//for the main hash, the nonce is a moving target.
//In essence this function allows for the use of 3 secrets: secret, nonce and offset.
    return llMD5String(data, (integer)("0x" + llGetSubString(llMD5String(llGetSubString(llGetTimestamp(),0,15) + secret, nonce),offset,(offset + 7)%32)));
}

Strife Onizuka

dual Key PGP?

Could this be written to use dual key (public/private) encryption? Or would that require a full implementation of PGP for LSL?

For example: an lsl wrapper could be written/added for GnuPG, assuming it is installed on Linden's servers. Then the object could be given the public key of the web resource it is accessing, and only the web server (also using GnuPG) could decrypt using its private key.

An encryted return could be achieved by having every member UID have a public and private key (public key published as part of a Linden web service, private key only known to the server -- not even the user would know it), and the web server would encrypt the message using the user's public key, and the object would access another wrapper function using the user's UID, the function accessing the user's private key and returning the decrypted message.

Any thoughts? -- Caelgarr Oconnell