I'm using the Authorization header with the Basic type for authentication.
I'm following the HTTP Basic authentication specifications which states that the credentials should follow this form -> userIdentifier:password encoded in base64
We are using an email as the user identifier and according to the email format specification, the colon(':') character is permitted.
The colon(':') is also a valid character in the password.
Knowing this, I'm looking for a creative way to parse the credentials part of the header that uses a colon(':') as the separator between userID and password.
In this case it's simple -> francis#gmail.com:myPassword
This is where it gets complicated -> francis#gmail.com:80:myPasswordWith:Inside
francis#gmail.com:80 is a valid email according to the email format specification even though this is not used very often. So where do I know where to split ?
We have made the decision not to accept an email containing a ':'. But we want to notify the user that his email is not valid, how can we ensure that we are splitting the string at the right place ?
Hope I asked my question in a clear manner, don't hesitate to ask for more details
Thank you
Don’t notify the user that the email is invalid. Split according to the RFC 2617 rules (everything after the first colon is the password), then try to authenticate, fail, and return a generic “authentication failure” message.
A situation where john#example.org:80 has password secret and john#example.org has password 80:secret at the same time, seems unrealistic.
If you require your users to register, you probably do it with some other mechanism (forms?) where you can easily separate the username and tell that it is invalid.
Related
The background first:
I have an application where a logged-in user(employee) X can see a list of all other users (employees). If the logged-in user X is a manager (their designation), then they can also edit certain attributes of the users they manage. For example, the location, designation, and the department of the user being edited. It should be noted X can edit only those employees who report to him/her, which means there are users which X is not allowed to edit.
When X clicks on a user to edit it, they navigate to a page like http:myapp.com/dashboard/editUser/<ID_OF_THE_USER_BEING_EDITED>
Obviously, X can get smart and manually edit the URL and put in the id of a user they are NOT allowed to edit, so before loading the edit form I need to check whether X has the authorization to edit user Y.
if X is authorized to do so, then that page displays a form (with the current attributes of the users pre-filled in the appropriate fields) to edit the user. Else, I display an 'Access Denied' kind of message.
Right now I have created a very badly named temporary endpoint (/api/v1/maybe_edit_user/?jwt=<TOKEN>&userId=<USER_BEING_EDITED>).
This grotesque-looking endpoint does 2 things:
It extracts the currently logged-in user from the token, and checks whether it has the required access level to edit the user (passed through the GET parameter userId)
If yes, then it returns the current attributes (name, email, location, designation, and other stuff) in the response, which is then pre-filled in appropriate fields when the form is displayed.
Once X submits the form, a PUT request is sent to another endpoint (/api/v1/users/<USER_ID_OF_Y> PUT) and the user Y is updated.
While this works, I don't find it attractive. I am trying to learn to write better, cleaner, and more organized code that is compliant with the standards.
The best practices for REST suggest that all endpoints should be nouns. My endpoint, on the other hand, is not even a simple verb. It's a god-forsaken phrase at the very minimum.
So, the questions here are:
How should I name my endpoint.
Should I use a single endpoint to check for permission, AND fetching the attributes of the user being edited, like I am doing right now? Or should I break them into 2 separate endpoints?
The fact that there is an access control list is an unrelated concern; ignore it.
Resource identifier identify resources. Resources are generalizations of documents.
You want an identifier that is consistent with the production rules of RFC 3986, and it is often convenient (but not required) to choose spellings that enable leverage of URI Templates (RFC 6570), but otherwise the machines don't care.
That means you can choose a spelling that makes things easier for humans; you get to choose which humans get priority here.
it returns the current attributes (name, email, location, designation, and other stuff) in the response
That's your hint as to what the document is; some sort of digest of Bob's... profile? employee record? dossier? that is apparently optimized for use in this specific kind of form.
So the identifier could be as simple as
/this-specific-kind-of-form/source-data/Bob
and a request might look like
GET /this-specific-kind-of-form/source-data/Bob HTTP/1.1
Authorization: Bearer <token>
The implementation looks largely like your sketch - verify the token, compare the claims to those that are required, and return either the resource or some flavor of Client Error (4xx).
The best practices for REST suggest that all endpoints should be nouns.
Don't read too much into that.
Notice that all of the following resource identifiers work:
https://www.merriam-webster.com/dictionary/get
https://www.merriam-webster.com/dictionary/post
https://www.merriam-webster.com/dictionary/put
https://www.merriam-webster.com/dictionary/patch
https://www.merriam-webster.com/dictionary/delete
You can click on any of those links, and your browser will create the correct HTTP request, and the server will do the expected thing.
How can I verify if an incoming field is a valid e-mail? Is there a way to use string-functions or anything in Firestore security rules?
Example:
Let's say I have a Create-Request with a field called "email". In my Firestore security rules, I would like to check if the email is a valid email address:
contains '#'
ends with either .xx or .xxx (a casual country-domain-ending)
has a '.' before the last three or two letters of the email
the '.' does not follow directly after the '#' - at least two letters have to be in-between
So that e.g. example#emailprovider.com gets accepted, but not example#.com.
I know that this check is quite extensive and further would like to know if it makes sense to introduce such a validation to security rules?
You can use rules.String.matches.
See
https://firebase.google.com/docs/reference/rules/rules.String#matches
https://github.com/google/re2/wiki/Syntax
How to validate an email address using a regular expression?
Performs a regular expression match on the whole string.
A regular expression using Google RE2 syntax.
If you want to set only email address then It's necessary to validate the field as email address.
I found an example of a regex (and adjusted a bit):
^[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,5}$
The source of this is at the bottom of the following page:
https://firebase.google.com/docs/reference/security/database/regex
You should also take into account the note as well:
Note: THIS WILL REJECT SOME VALID EMAILS. Validating email address
in regular expressions is difficult in general. See this site for
more depth on the subject.
I know that URI supports the following syntax:
http://[user]:[password]#[domain.tld]
When there is no password or if the password is empty, is there a colon?
In other words, should I accept this:
http://[user]:#[domain.tld]
Or this:
http://[user]#[domain.tld]
Or are they both valid?
The current URI standard (STD 66) is RFC 3986, and the relevant section is 3.2.1. User Information.
There it’s defined that the userinfo subcomponent (which gets followed by #) can contain any combination of
the character :,
percent-encoded characters, and
characters from the sets unreserved and sub-delims.
So this means that both of your examples are valid.
However, note that the format user:password is deprecated. Anyway, they give recommendations how applications should handle such URIs, i.e., everything after the first : character should not be displayed by applications, unless
the data after the colon is the empty string (indicating no password).
So according to this recommendation, the userinfo subcomponent user: indicates that there is the username "user" and no password.
This is more like convenience and both are valid. I would go with http://[user]#[domain.tld] (and prompt for a password.) because it's simple and not ambiguous. It does not give any chance for user to think if he has to add anything after :
I have a very simple (rather stupid) question, I hope someone can clear my mind on this :)
I want to send an email to my site user once he clicks a button. This email will contain a link with the userID of a user in the link URL (as query param of a link).
Once the user clicks this email link, my server side code will parse and decrypt the userID query string key to get the user ID and perform some action on it.
I cannot use base64 encoding as it can be reversed and 'hackers' can get to know the real userID. I have to encrypt the ID but when I am using AES alogrithms for encryption, the encrypted text is not "understandable" by the browser, ie I cannot pass the encrypted userId text as a part of the URL because it contains un-encoded characters like "/" which the browser cannot by pass. One option I can think of is to base64 encode the encrypted text once I send it across via URL. Then I can bease64 decode and decyrpt it.
Is this approach better than using Uri.EscapeDataString() on the encyrpted text?
You should continue to base64 encode the AES data, as at that point it is likely binary rather than a string that can be escaped. You should also check that you are using url safe base64 encoding.
Use a one-way hash like SHA1 or MD5, and use JavaScript to send the values as encrypted. Then, if a hacker intercepts the request, they would only have the hashes and not the actual values. They could still send the hashes to login, though; one solution is to include a JavaScript parameter (generated via your server-side language) based on IP (but not possible for a hacker to find the formula for), and use it to salt the username and password hashes.
Then on server-side you would do (in PHP, in this case):
$ipHash = sha1("random" . $_SERVER['REMOTE_ADDR'] . "salt_here10381") // place this as a hidden element in the form and use it in the JavaScript to calculate the hash
$userHash = $_POST['userHash'];
$passwordHash = $_POST['passwordHash']
// TODO: Escape $ipHash, $userHash, $passwordHash
$results = mysqli->query("SELECT * FROM `users` WHERE SHA1(CONCAT('" . $ipHash . "', `user`)) ='$userHash' AND SHA1(CONCAT('" . $ipHash . "', `password`)) = " '$passwordHash'");
Then, if a hacker wanted to login with the hash and username they found, they would need the same IP of the user originally logging in whose credentials were intercepted.
Note that this assumes you have passwords stored in your database as plain-text, which you should never do.
For hashing with SHA1, on client-side, take a look at this.
To answer your specific question (I see I got a bit off topic, oops,) it would be acceptable to base64encode the hashes when you send them to the server. If possible, try to send it as POST data and save it in a cookie or session variable.
I think of a simple solution you try to generate a random number(make it as a key) and for the encryption use some simple technique of yourself like XOR 'ing the ASCII value of the characters in the user name with the key that you have generated .so the long random key results in a greater result.
When creating the email you need to encrypt the user ID, then base64 encode it, then URL encode it. Put this as the userID param in the link.
When decrypting the email you do the same in reverse; get the userID param, URL decode it, base64 decode it then decrypt it.
Remember to use a different intitialisation vector every time you encode a user ID. You will need to put the initialisation vector in the emailed link as a URL parameter too in order to decrypt it.
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.