I have a following url:
/Reports?reportId={value}
The problem is that not every user can see every report, but with this kind of url he can actually enter whatever ID he wants and access that report.
So my question is should I just add a server side validation to check if currently logged user has access to this report and if not return some Anauthorized response, or send this via POST so he cannot see the url and change it (if this approach is safe enough).
And generally I want to know if it is bad idea to send ID in url? Maybe it is better to use Guids for ID-s then instead of integers?
So my question is should I just add a server side validation to check if currently logged user has access to this report and if not return some Anauthorized response
Yes, a thousand times this.
or send this via POST so he cannot see the url and change it (if this approach is safe enough).
No. Never this. This is security through obscurity. POST data is not hidden in any way.
if it is bad idea to send ID in url? Maybe it is better to use Guids for ID-s then instead of integers?
No, that does not matter at all. That also is security through obscurity. The GUIDs still show up in plaintext, so anyone with access to browser history, firewalls, or the network in general can inspect and replay the traffic containing GUIDs.
See also Why not expose a primary key - Programmers Stack Exchange.
In addition to CodeCaster's answer:
IDs in URLs can indirectly reveal some business related information. For example from contract ID=963 your competitor may learn that you did since last month 40 new contracts (ID was e.g. 923) and earned cca 50k. This is sometimes not desired.
It's quite common though to mask ID e.g. by converting into a masked string. I usually use openssl_encrypt and openssl_decrypt respectively.
Here's example for converting ID to/from masked string:
public static function encryptOpenssl($textToEncrypt, $encryptionMethod = 'AES-256-CFB', $secretHash = "12#rk!", $raw = false, $password = ''){
$length = openssl_cipher_iv_length($encryptionMethod);
$iv = substr(md5($password), 0, $length);
return openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash, $raw, $iv);
}
public static function decryptOpenssl($textToDecrypt, $encryptionMethod = 'AES-256-CFB', $secretHash = "12#rk!", $raw = false, $password = ''){
$length = openssl_cipher_iv_length($encryptionMethod);
$iv = substr(md5($password), 0, $length);
return openssl_decrypt($textToDecrypt, $encryptionMethod, $secretHash, $raw, $iv);
}
You can of course use any other obfuscating algo, e.g. rot13, exchanging character positions, character mapping, prepending/appending irrelevant chars etc.
Related
I want to test (unit testing) HashPassword($password) method from WordPress.
How I can check that HashPassword("123123") will return the correct hash for it?
For example, I want to do something like:
$hashFor123123 = "$P$P)230230832482349823";
$result = HashPassword("123123");
$this->assertSame($hashFor123123, $result);
But, HashPassword method each time returns a new string with hash. That is why I cant do assert.
How to test it?
Password hashing uses a random salt, so each time you hash the same password you'll get a different value back. The theory is explained here, even though WordPress doesn't use the php password hashing functions, but rather their own. You cannot compare hashes; you can only check whether a given unhashed password matches a hash.
The random salt defeats cybercreeps' use of rainbow lookup tables to recover passwords given their hashes. This helps keep your users' passwords secret even if a cybercreep manages to steal your wp_users table. Defense in depth, it's called.
In WordPress, you can hash a password and then check it using wp_hash_password() and wp_check_password(), something like this.
$hash = wp_hash_password( '123123' );
if ( wp_check_password( '123123', $hash )) {
/* it worked */
} else {
/* it did not work */
}
It's not clear why it is worth your time to unit-test this subsystem. It is used in production many billions of times every day around the world.
The reason that the result is different every time you call HashPassword is because your password is prefixed by a random salt before it's hashed.
To compare a plaintext password against a known hash, you have to call CheckPassword.
I'm working on an asset management website where in whenever an asset is issued to a user the system would send an email notification with a url in it that would show the user all the assets issued to him. I could have used the query string to pass the user ID but again people could abuse it to view assets issued to other users. My client doesn't wants the user to authenticate themselves when they click on the link. So i need something that would hide the parameters being passed in the query string or at least make them obscure. I've read about url encoding, GUID etc. but i'm not sure what to do. I'm just a beginner. Please pardon my ignorance and point me in the right direction.
Taken what you have said, that you're just a beginner, and assuming that this will be public, you can do the easiest way:
Create a new table in your database and called for example tbl_links, as columns just add 3
user_id (foreigner key to the user table)
guid (primary key, unique)
settings (nvarchar(250)
When you need to send an email, create a new row for the user, for example:
Guid guid = Guid.New();
String settings = "date_from:2012/01/01;date_to:2013/01/01";
And insert it one the database, where the link that you put in the email, should have the guid, for example, http://domain.com/info/?g=....
You could append Json to that settings column and parse it into an object again in the code, ask a new question if you want to take this route.
I personally use a security algorithm to pass only the user_id but you did said you're a beginner, so I only showed you the easy and still valid way.
P.S. for security reasons, you should say in the email that your link is only valid for the next 4 hours or so you can prevent people from generating GUIDs in order to try and get some information.... Simple add a create_date column of type datetime and use that to see if the link already expired or not...
For obscuring URL parameters, you want to use a modified Base64 encoding. Please keep in mind that obscurity is not security, and Base64 encoding something does not in any way make anything secure.
If you're intending to use this for authentication purposes, I think you should reconsider. Look into public key encryption and digital signatures as a starting point.
Trying to secure access to a URL is not the right approach. Give the urls away freely and authenticate your users instead.
I would also highly recommend using SSL for serving up this data.
Security through obscurity fails 100% of the time once the obscurity is not longer obscure.
What you can do is to add some prefix and suffix to the id and the encrypt that string. Something like this:
static public string EncodeTo64(string toEncode)
{
byte[] toEncodeAsBytes
= System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
string returnValue
= System.Convert.ToBase64String(toEncodeAsBytes);
return returnValue;
}
static public string DecodeFrom64(string encodedData)
{
byte[] encodedDataAsBytes
= System.Convert.FromBase64String(encodedData);
string returnValue =
System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes);
return returnValue;
}
string prefix = "lhdsjñsdgñdfj";
string suffix = "dfknsfñn3ih";
var strToEncode = prefix + "|" + id + "|" + suffix;
var encoded = EncodeTo64(str);
var decoded = DecodeFrom64(encoded).Split('|');
if( decoded.length != 3 || decoded[0] != prefix || decoded[2] != suffix )
throw new InvalidArgumentException("id");
var decodedId = decoded[1];
We have some error reporting code that, when an unhandled exception occurs, we send everything over in an email to our groups. This is great except if an unhandled exception occurs on a page with a password field then it's sent over as plain text.
Is there a way to iterate through Request.Form and figure out which item(s) are passwords? This is done at a low level so we can't look for specific controls.
Naturally, we could check to see what type the input box is but I'm not sure if that's the cleanest way. Advice?
Use a whitelist of field names that you want to email.
There could be hundreds of field names that get POSTed to your server. And password isn't the only field that is sensitive. Depending on your application, there could be other things that should be treated with a little respect.
So, make a list of field names that will assist in you in debugging. These are typically unique identifiers / database keys and such. If you have any parameter names in this list, you can include it in the email.
I've suggested a different solution earlier, but I thought you were going to handle this on the client side. Following your comments I now understand that you need to take care of this on the server side. There may be a way for you to do it, which is not really elegant, but it should work:
Add to all pages a script that collects all password field names into a new client-generated field, like so:
function collectPasswordFields() {
var inputs = document.getElementsByTagName('input'), list = [];
for (var i = 0; i < inputs.length; ++i)
if (inputs[i].type == 'password') list.push(inputs[i].name);
var field = document.createElement('input');
field.name = '__password_fields';
field.value = list.join(',');
document.getElementsByTagName('form')[0].appendChild(field);
}
Then intercept the additional field in the server-side error handler, and remove the named fields from the email.
Can something like this work for you?
The cleanest way is to check the type attribute of the input element.
The HTML5 specification has this to say about input type=password:
The input element with a type attribute whose value is "password" represents a one-line plain-text edit control for entering a password.
Data type: Text with no line breaks (sensitive information)
Control type: Text field that obscures data entry
This is a mandatory requirement from all User Agent implmentations, and it has been so since HTML 2. So this is indeed the cleanest way to do what you want.
If you want to do it on the client side (you talked about sending the data to the server) then it is relatively easy:
function hidePasswords() {
var inputs = document.getElementsByTagName('input');
for (var i = 0; i < inputs.length; ++i)
if (inputs[i].type == 'password') input[i].value = '*****';
}
As Jerome already pointed out in the comments, just keep track of the names of your password input fields and filter them before sending the error/exception report. This is the best solution as the type of the input field is not submitted.
A few solutions, though I'm not sure how bright any of them is:
1) Maintain in the page a List of input control IDs that are passwords, pass this list to the exception handler with the expectation to ignore these fields.
2) Keep a resource file in the website that lists a page name, a field id and have the exception handler check against this resource file (may not work if the exception is related to the ResourceManager)
3) Keep a database table as with idea 2. Same problems exist.
We use Captcha control in a registration form that we make full client validation for all fields in JavaScript ( JQuery ) beside server validation ..
I tried a lot of ways but all will write the Captcha value in JavaScript that can be accessed by anyone :(
I search if is there any way that allow me validate Captcha value in client side using JQuery in secure way or it can't be done ?
It cannot be done.
Javascript is client-side, as you know, and any code client-side has to be treated as potentially compromised as you don't have control over it.
At best, you could resort to sending up a salted hash of the value along with the salt, but even that in itself could be used to test guess values before actually submitting it.
Everything else relies on calls to the server.
As per comment request, here's the general idea:
Firstly, on the server, calculate a random string to be used as the salt. This should be roughly unique every request. The purpose of this string is to prevent rainbow table attacks.
Now, saving this string separately, but also create another string that is the concatenation of random string and the Captcha answer. Of this new combined string you generate the hash (for example, SHA-1) of it.
using System.Web.Security;
...
string hashVal = FormsAuthentication.HashPasswordForStoringInConfigFile(combined, "SHA1");
Both the random string and the hash value need to be placed in the page for the javascript to be able to read.
On the client side, when a user answers the Captcha, take the random string and concatenate it with the answer (getting the idea here?). Taking this string, you can use something like the SHA-1 JQuery plugin to hash it and compare it with the pre-computed hash you sent up.
hashVal = $.sha1(combinedString)
If it matches, it is (almost) certainly the correct answer. If it doesn't, then it is 100% the wrong answer.
you could use ajax to post the current value to the server, which would respond true or false. that would keep you from doing a real post and also from giving away the catpcha's value in html.
My solution )) Every time when page shows captcha to the user, you can dynamically generate obfuscated JavaScript functions(i think the best way 5 or 10).
For example, one function(or 3)) ) can set cookies with pregenerated hash(server returns it)(from real value of the captcha), other functions must realize server side algorithm to check value which user's typed. I can say that it works for 100%, because it is very hard to parse dynamically javascript + we set user cookies on client side(It is very hard for Bots's to find out where and how you set and check cookies), by using JavaScript.
For a Web Application I'd like to generate an email validation link and send it to the user. Like on many public websites, the user should click it to validate his email address. Looks similar to this:
http://www.foo.bar/validation?code=421affe123j4h141k2l3bjkbf43134kjbfkl34bfk3b4fkjb43ffe
Can anybody help me with some hints about the proper generation of those validation tokens? Googling best practices turned out to be more difficult than I though it would be. The links should:
... not require the user to log in first.
... not reveal any login credentials to keep the application secure
... allow me as a developer to efficiently validate the token. I'm pretty sure I need a way to extract the user identifier out of the code to meet this criteria. Don't I?
Furthermore, would you go for a random code, which is saved somewhere, or a generated code which I can recalculate for validation?
Thanks for any replies!
Matthias
P.S. I'm working with ASP.NET 3.5, in case there's an out-of-the-box feature to perform this.
Some suggestions to get you started:
Use GUIDs
Use some sort of salted hash (MD5, SHA1, etc)
Use a random string of characters (the more characters the less likely you'll have collisions)
Store it in a database temporarily, and timestamp it so that it expires after a certain period of time
The simplest way to do it is generate a GUID, store that in the database tying it to their user account and then give them a time-frame within which to click a link with that GUID in.
That validates they are the correct person without making the URL calculable whilst making it resistant to dictionary style attacks.
I construct the hash in a way that can be re-created:
code = MD5( my_hash + user_email + register_timestamp )
Then send a link to http://example.com/validation/?code = 4kj34....
Validation does a lookup like:
SELECT id
FROM users
WHERE
MD5( CONCAT( my_hash, user_email, register_timestamp ) ) = code
AND activated = 0
If you get a single result, update their 'activated' field and sign them in. You can also do some math on their 'register_timestamp' field for a poor man's TTL
I would probably use a Guid. Just create a Guid (by calling Guid.NewGuid()), store it as the validation token for that user, and include it in the validation link.