I have a very unique situation. I am building an application where a user uploads a QR code to my site, and when decoded, it has a matching ID already stored in the DB (as in I already have a record of the qr code before the user uploads it)
When they upload it, I decode it, which is a base64 string like so 6BbW0pxO0YENxn38HMUbcQ==
Like I said, That code corresponds to some information, and after they upload the QR image, I redirect them to one more page, which shows them the qr code, the corresponding information stored in the DB, and they are also prompted with a submit button. When pressed, I take note that they have confirmed, and I do some other things.
To elaborate
As a user I go to www.url.com/code/upload and upload an image. I am then redirected to /code/new with the page displaying the data stored in the DB from the correspond decoding of the image.
How can I make the submit button on /code/new reliable? Here are the solutions I can think of, and their vulnerabilities
Propagate /code/new with the correspond data stored in the DB, lets say #username and #movie into a form, with a submit button and POST the data to the server
This is dangerous because I don't think anything stops someone from editing the DOM and changing #username and #movie to something else
Pass the unique base64 identifier in the parameters such like, /code/new?id=STRING
Then when you submit, the string gets passed to the handling controller action, but i feel that this is not safe because then users can attempt to guess the strings and make concurrent post requests.
Essentially, I have a user upload a qr code, and after submission, I need to verify to verify that they were the one that uploaded the image. I lose all state, and information after they upload the image.
A proposed solution:
After the user uploads the image, create a unique string and store it in the session and also a record in the database (A user is logged in, so its the current_user.session_token), then when the user clicks submit on /uploads/new, I grab the session token, and verify that the current_user.session_token == session_token.
At this point, I can only verify that the current user was the one that uploaded the image.. I then need to somehow grab the base64 string that was from the uploaded QR code.
Another proposed solution: I temporarily put the base64 string as an attribute of the user when they upload the file. So I will have current_user.session_token and current_user.base64_string. Then when the user clicks on the 2nd submit button, I do something like
#check if the user's token is equal to the sessions, and the string is not nil
if current_user.session_token == session_token && !current_user.base64_string.nil?
data = current_user.base64_string
#hooray! I have the QR code
end
Then delete the session token, and then delete the current_user's base64_string and session_token
if a malicious user attempts to forge their session token, it won't match their's store in the database, then when I handle the post request, I will not proceed. But If a legitimate user makes the second post request, the session Id matches, and I am able to grab the base64 string.
TL;DR, I need 2 concurrent post requests that carry the information without losing it, and can verify that both the first and second post requests were done by the same user.
If anyone had the patience to read through that, I appreciate it! if there are any suggestions I would greatly appreciate it, or if you think my solution is sufficient or not, please let me know. Thanks!
Sign the parameters generated from the first request, and verify the signature when you process the second request.
The technology to use for this is HMAC. Here's how to use one version available in Ruby:
require 'openssl'
secret = 'ABCDEFGHIJKLMNOP'
data = 'user:code'
signature = OpenSSL::HMAC.hexdigest( 'sha256', secret, data )
p signature
Output:
"bd7194c0604902d6594694d25e7f27bdc2d10926638e0ce8bdda3f6debb37f6a"
This is how you can use it to link two HTTP routes together so that the second one can trust that parameters sent to it via the first one have not been tampered with:
When the first route is called, generate or fetch a secret. It is important that this secret value is not ever sent or exposed to the end user. It can simply be application configuration (which then applies to all linked requests), but if you can store it associated with perhaps the QR code, then the strongest protection is to generate a long random string just before creating the signature, and to store it ready to use to confirm the second step. Something like SecureRandom.hex is great for a short-term secret if you have somewhere server-side to store it.
Combine all the parameters on the form that you want to be tamper-free into one long message. Easiest thing to do is .join them in an array, and you should use a delimiter that is not allowed in any value, and that you are also not accepting due to validation. This string is the value to use for data in the example.
Generate the form that calls the second route. In addition to the params you want to accept at next stage, add the signature value generated as above. Do not send the value of secret to the client by putting in the form or cookie etc.
When you receive the request from the second route to finalise the multi-stage request, generate the signature from the user-sent params (after validating them), and compare with the one sent to you from the form. If it is the same, then the request is valid. If it is different then the data may have been tampered (provided you have no bugs - do check things such as consistent character encoding if any param can contain non-ASCII characters)
Provided you have kept the secret truly secret from the end user, they have next to no chance of generating a correct signature. Only your code in routes one and two knows how to do it (because it has access to correct secret, not because of any special fact on how it is written). Therefore you can trust that the values have not been modified.
Related
Like the question says, how do I add a parameter to a URL?
Example:
When you click on a link to get a featured product on Product Hunt, the URL is appended with ?ref=producthunt.
Can I just add a parameter like this manually to the few links that I have on my website? Are there any scenarios where this might be suboptimal to do?
The parameters in the URL correspond to the superglobal $_GET array.
It means that if your URL is in the form
www.domain.com?key1=val1&key2=val2 ,
then $_GET[key1] contains val1 , and so on.
It is perfectly legitimate to add these parameters manually in a link (a typical use case would be a login button, which redirects you to the current URL and appends &todo=login . You can then add a bit of PHP code that triggers the login process when $_GET contains the value 'login' at the key 'todo').
The other way of adding these parameters is forms. In an HTML form, you specify a 'method' which can be 'get' or 'post'.
If you choose 'get', when the form is submitted, the URL will automatically be appended with the form answers.
NB: It is generally NOT SAFE to directly read values from the $_GET, as the user can fill it with any value (just by changing the URL) so it is good practice to use filters that ensure inputs are safe. Check http://www.w3schools.com/php/php_filter.asp for more on filters
The parameters added to the url is called query string and they have a format
it must start will ?
every paraper will be seperated with &
Example: http://www.yoururl.com?name=myname&age=34&ect=somethingelse
The mistake you did is by putting ?= which is not converted by your web server.
you can pas like '?websitename=website-name'
Querystring parameters are key value pairs that are separated from the URL's domain and path with a ? and separated from each other with an &, i.e ?key=value&key2=value2.
The values can be accessed client-side (in Javascript) and server-side by the webserver or by a server-side language is being used, PHP, ASP.NET, Java.
Some values should be encoded using a function such as encodeURIComponent to ensure that they are valid.
Risks
You need to be careful that the querystring does not contain any sensitive information such as a sequential order number, i.e ?order=5 as someone could manually change the value to see another user's order (?order=6, if no other authentication in place). The order value should be encrypted so it cannot be guessed. Also, do not execute any code passed in on the querystring with eval() as the contents could be changed by a malicious user to execute a crosssite scripting (XSS) attack on another user and steal their cookie or login credentials.
How would you think a hacker is doing the following, and how would you prevent (looking for some helpfull links, keywords or assessment of the sitution)?
Their is a website where users can register and get an invitation Email. The invaitation link (https) contains the token. It looks like 'https://www.example.com/token/123456' (123456 is the token).
It seems that a day after my users clicked on this link, someone else uses the same links too.
How is this possible and how can I prevent this sort of hack?
Thanks
EDIT:
Sorry I should have given more information. I can eliminate the opinion that it is not just a try of random token variations. Why? The exact token is used a day after one of the user had use the link. The token is a hash token of more that 20 characters.
They can just run a script to try any numerical value in the token value.
it's easy. How long is your token? I would also suggest using a hash token rather than a simple numerical one to limit automatic processing, as the "hack" is scripting to try a number, gets a result - store the result, and then number = number + 1;
Edit: What evidence do you have you've been hacked? What happens in your script once someone has clicked the token link?
A simple logic to apply could be:
define a string pattern. like: secretconstant%email
hash the string and now you have the token (and save it)
create your invitation url with the token
If someone call your service with random token you can reject them because your information system don't have saved that token.
Then if you have the token you must discard it so the link will not be valid anymore.
You could check also if the email used in the registration is the same used for calculate the token.. so you may block the registration!
snatching my hair to fix this problem but I can't.
I am parsing id in url to pull data on next page according to that id. So rather than parsing id=123 I encrypted it something like process.php?token=TG4n6iv_aoO7sU3AngFY4WLSppLvueEoh-MnYE6k7NA, and decrypted it on process.php page by collecting it with $_GET, before using it in sql query. This is not proper URL, I need url like process.php?token=9878799889 and I need to decrypt this 9878799889 on process.php which would give me my original user id.
So here I can not use md5 or base64_encode which give me ugly string.
What would be best thing to do here?
id is unique so generated long digits should be unique as well and not easy to guess.
Right now I am using encrypt logarithm with salt. Actually want to parse like www.sitename.com/process/token/9878799889..this can be achieve with .htaccess so not worried about it..
Any help will be much appreciated..
What you could do is add an association table in your databse, which would contains a UUID as primary key (a randomly generated number) and your true ID reference (and other information you may want to store there, like a "valid until" date or other things...)
You'd have to generate the entry in that table as you parse the UUID
let's say INSERT INTO uuid_table (uuid, real_id) VALUES (9878799889, 123);
now when you process the url process.php?token=9878799889
you would only have to SELECT real_id FROM uuid_table WHERE uuid=9878799889;
it would retern the read id 123
You should also DELETE FROM uuid_table WHERE uuid=9878799889 when you're done.
Note that it would also work with md5 or base_64, but indeed it makes the url uglier.
I am working on an email validation link for a website. When a user registers and finishes filling in their personal data (and it passes all the checks), they are sent to a jsp page saying that an email has been sent to the address they entered as the username, with a link to click to validate the email address. So that part is all well and good, I generate the link (for now just using my localhost) and it looks like this as an example http://localhost:9999/javawork/msc/validate/?6FRQ8RAT&u=1s3w1Iih64egX01188HT. When they click the link it goes to the jsp page index.jsp in the validation folder. At this point I need to grab the entire URL and send it to a function to make sure the URL is formatted properly (for security purposes). If it passes and the format is fine, I need to grab the 8 digit code immediately after the '?' and also the value of 'u'. I then send those values to a function that checks that they match what we have in our DB, and if they do, I update the DB record with a validation date so we know they have validated their email address.
So my question is first, how do I grab the entire URL to check the format, and second, how do I grab the 8 digit code, and the value of 'u'? I have been looking online and all examples require creating multiple functions or classes, and using the URL class. And they all want me to make an instance of a URL object and initialize it using the entire URL. But it is not a static URL, it will be different for every user that registers, as it generates a random 8 digit code to check against, and the value of 'u' is the masked user id from the DB. I don't understand how it can require you to initialize the entire URL in order to get the values, when you don't know what the values are until you get them from the URL.
Is there a simple way to grab the values, and the entire URL? Even if I can just get everything after the '?', I know the base URL and can build a new String to check the formatting if I can get from the '?' and after. Please help with that part. Thanks.
The Interface HTTPServletRequest contains a method getRequestURL which returns a StringBuffer which you may use to check the format of the entire URL.
You can get it, in a jsp page with :
<%=request.getRequestURL()%>
If you are using the format of request that you specified above, then your second question :
how do I grab the 8 digit code, and the value of 'u'?
May be answered by manipulating that StringBuffer to split at the ? and & for the 8 digit code.
Or use another request method,
ServletRequest.getParameter(java.lang.String name)
To grab each parameters, though, i'm not certain how it will end up handling the unnamed parameter of the 8 digit code. Let me know how that goes.
Don't think of the 8-digit code as an unnamed parameter. Think of it as a parameter without a value.
request.getParameterNames() will give you the 8-digit code as well as "u". So you can loop through like so:
String code = "";
for(String paramName : request.getParameterNames()) {
if(!paramName.equalsIgnoreCase("u"))
code = paramName;
}
My web-site has AJAX-powered search, that uses deep-linking. When user follows a link …
http://example.com/articles#/?tags=Mac%20OS,review
… tags "Mac OS" and "review" should already been selected in a search form and articles, related to "Mac OS" and "review" should be presented on the page.
I have following scenario, that a need to fix
User follows the link http://example.com/articles#/?tags=Mac%20OS
During initial page rendering, all articles are fetched
On the client side, hash-part is parsed and only "Mac OS"-related articles are requested via AJAX.
Client receives "Mac OS"-articles and replaces all articles, fetched at step 2. Also it marks "Mac OS" tag as selected on a search-form.
The problem here - is duplicated articles rendering, that looks really bad for the user. He looks at all articles, and after couple of seconds, they will be replaced with "Mac OS"-articles.
I need to have following scenario:
User follows the link http://example.com/articles#/?tags=Mac%20OS
Server parses hash-part and returns "Mac OS"-related articles
Client understands, that "Mac OS"-articles are already there and does nothing. It just marks "Mac OS" tag as selected.
To do this, i need to get hash-part of the request string:
/?tags=Mac%20OS
I cannot use request parameters after ?, because i use AJAX and deep-linking. With ?-part, browser will be forced to reload the page. I need to do anything without reloading the page.
You help will be greatly appreciated.
Thanks.
The part of a URL after the hash is not sent to the server, so you can't process it there. You can extract that part of the URL in the client-side code that creates your Ajax request and send it as a parameter.
#NickFitz is correct, but if you must send whatever comes after the # hash/pound symbol, you can use the URL encoded characters that represent # which is %23.
So %23 and whatever that comes after %23 will be sent to the server. If you are using modern web server, they will automatically recognize that %23 is #. In Ruby on Rails, Rack does this for you.