I've tried to figure out how kerberos authentication works, the information which I found was always missing something as if a part of it was taken for granted. I am aware of the process in general but missing some details.
Getting TGT:
First a user should get a TGT (Ticket Granting Tickets) from the KDC - the user sends a request with only it's user name (UPN) and without it's password. Some extra information is given to prevent a resent of the request such as ip address and a timestamp.
If preauthentication is required then the time is hashed with the user's password.
The KDC is sending the user back the following:
A. TGT - with a timestamp, user name, ip address and a session key - the TGT is encrypted with a secret only the KDC knows and therefore cannot be changed by anyone.
B. Session key for the user and the KDC to be used in later communication.
Those things are encrypted using the users password (a basic shared secret amongst the KDC and the user).
In case a preauthentication was used the server will check if the timestamp was valid before sending the information back.
The users receive the information and decrypt it using it's password - and then stores it in it's memory (kerberos tray).
Getting TGS:
When the user is requested to authenticate itself from a service he sends a request to the KDC for a TGS (Ticket Granting Service), the request contains the TGT, UPN and the SPN (Service Principal Name - say, the URI of a webpage).
The KDC then decrypts the TGT and validate it's authenticity, that it is corresponds with the UPN, from the same IP address and still valid (the ticket has an effective time period).
The KDC sends a TGS to the user encrypted with the service password.
The user presents the TGS to the service - which decrypts it using it's own password.
The authentication is complete since the service counts on the fact that it's password is only shared between it and the KDC so it trusts that the KDC authenticated the user earlier.
A few questions:
Am I missing something or that's it?
When does the user and the KDC ever use the session key? At what point? Why is it necessary? Why does the user password isn't enough?
There should also be a session key between the user and the service (to the best of my knowledge) - when and why is it used (same as the last question)?
Kerberos has a 5 minute gap limitation between all parties - I understand why keeping the time in sync is important since it is used as something that we encrypt and decrypt so how come any gap is OK? Why 5 minutes?
I'll be glad for any corrections if you have.
Thanks in advance,
Tomer
So, I think I've found the answer.
I'll make a few corrections since the question has some inaccuracies.
Getting TGT:
First a user should get a TGT (Ticket Granting Tickets) from the KDC - the user sends a request with only it's user name (UPN) and without it's password. Some extra information is given to prevent a resent of the request such as ip address and a timestamp. If preauthentication is required then the time is hashed with the user's password.
The KDC is sending the user back the following:
A. TGT - with a timestamp, user name, ip address and a session key - the TGT is encrypted with a secret only the KDC knows and therefore cannot be changed by anyone.
All of this are simply called an "authenticator".
B. Session key for the user and the KDC to be used in later communication.
Those things are encrypted using the users password (a basic shared secret amongst the KDC and the user). In case a preauthentication was used the server will check if the timestamp was valid before sending the information back.
The TGT itself is only hashed by the KDC's secret and not also at the user's password.
The users receive the information and decrypt it using it's password - and then stores it in it's memory (kerberos tray).
Getting TGS:
When the user is requested to authenticate itself from a service he sends a request to the KDC for a TGS (Ticket Granting Service), the request contains the TGT, UPN and the SPN
The request also include a fresh authenticator (instead of the UPN mentioned) which the KDC will check against the one that is in the TGT. The authenticator is encrypted using the session key of the user and the KDC. The KDC will decrypt the TGT using it's password and then extracts the session key from it (it does not saves the information on it) and next decrypts the authenticator using the session key.
(Service Principal Name - say, the URI of a webpage).
An SPN doesn't contain a URI - it contains the host, the service and a port - something like that: HTTP/localhost:80 Or ldap/localdc.
port number could be omitted if default port is used (such as 80 for HTTP or 389 for ldap).
The KDC then decrypts the TGT and validate it's authenticity, that it is corresponds with the UPN, from the same IP address and still valid (the ticket has an effective time period).
3. The KDC sends a TGS to the user encrypted with the service password.
The KDC also sends a session key for the client and the user to use later on. it sends it encrypted in the session key of the KDC and the user from earlier - another copy of the session key (of client and the server) is inside the TGS itself, inside the TGS also resides an authenticator of the client.
The user presents the TGS to the service - which decrypts it using it's own password.
5. The authentication is complete since the service counts on the fact that it's password is only shared between it and the KDC so it trusts that the KDC authenticated the user earlier.
The user also sends an authenticator encrypted with the session key of the client and the server. The server then decrypts the TGS using it's password - extracts the session key from the TGS and uses it to decrypt the authenticator and compares it to the one in the TGS. If valid then the authentication of the client is complete. Kerberos also features an option for the client to authenticate the server (called mutual authentication) - if a flag of mutual authentication is sent by the client then there is another step.
The server sends a timestamp to the client that is encrypted using their shared session key. The server proves it's authenticity by manipulating the data that the client sent (means it could've decrypted it) so it means it knows the servers password which only it and the KDC should know.
A few questions:
Am I missing something or that's it?
When does the user and the KDC ever use the session key? At what point? Why is it necessary? Why does the user password isn't enough?
There should also be a session key between the user and the service (to the best of my knowledge) - when and why is it used (same as the last question)?
Kerberos has a 5 minute gap limitation between all parties - I understand why keeping the time in sync is important since it is used as something that we encrypt and decrypt so how come any gap is OK? Why 5 minutes?
Yes.
Answered on the when, as to the why - the motive is to give an optional attacker a fewer samples of data which is created using the password so it would be harder to crack the password from the encrypted data. the session key changes all the time (each logon or after the expiration of the TGT) and by the time an attacker could crack it it will not be useful.
Answered.
Well, some gap has to be ok since the synchronization is not complete. I have a guess about the 5 minutes here - The KDC and the server should keep in memory the last 5 minutes of requests in order that an attacker won't resend a valid request and will get authenticated (called replay attack). So each time a request is made the server or KDC has to look in memory to see if it's not a resented request. Obviously there is a trade-off since the bigger the time gap the more memory the server needs to allocate to this task. By the way - the time period is only 5 minutes by default and is configurable.
Hoped it helps.
All of the things are in this link (very repetitive if one is reading the whole thing from the start to the end - you should read only the part that you want to understand) - Https://Technet.microsoft.com/en-us/library/cc772815(v=ws.10).aspx
And I also read a bit of the RFC - https://www.rfc-editor.org/rfc/rfc1510
And two less detailed links:
https://technet.microsoft.com/en-us/library/cc961976.aspx
https://technet.microsoft.com/en-us/library/aa480475.aspx (deals with IIS authentication - there is a part where kerberos is mentioned and explained a bit).
Related
I have a REST server over SSL.
Initially, the client logs in with the credentials.
To avoid sending the username/password for each request, I have created a custom token which is returned to the user in the login procedure.
This token contains some information about the client (IP and user-agent) as well as an expiration time; and of course the token is sent encrypted.
Further calls include the token in a custom header field; which are verified in IDispatchMessageInspector
The approach works fine, but I am pretty sure it's not a good approach.
Is there any benefit in using custom authentication than the message inspection?
Message inspection is the checking, changing, and replacing of messages after they are received and before they are sent.
Custom authentication requires the authentication of a username and password, which is more suitable for login or other situations where a username and password are required.
Both types of verification have their own applications.As you said to avoid sending the username and password every time you can choose message inspection. Personal words also tend to be message inspection.
Can you explain me the exact reasons and benefits of using hashes of password instead of the passwords themselves?
Because parcticly if you got hash of user you can authenticate as that user, and anyway the password is invisible.
It's more secure to store a hash of a password rather than a password itself (e.g. in keytab).
Kerberos only transfers over network encrypted Authenticator with its own copy of a secret key. Authenticator contains unique information about the client (for example, client name, client realm, the time on the client, and so forth). Each Authenticator is unique, because of the time information it contains.
So information transferred over network can't be reused (replayed later by an attacker), as Authenticator is unique and depends on time.
Hope this helps. With Kerberos you don't have password stored nor transferred over network. Which makes it more secure.
I don't understand the point of having access token in authentication. Below is a paragraph of explanation I took but I still confused. Since every api call still go to the db look for the token, what's the different check for the username and password for every http request?
Instead of forcing clients to send username and password with every
request you can have a "get_access_token" function in your RESTful
service that takes the username and password and responds with a
token, which is some sort of cryptographic hash that is unique and has
some expiration date associated with it. These tokens are stored in
the database with each user. Then the client sends the access token in
subsequent requests. The access token will then be validated against
the database instead of the username and password.
Using the access token limits the amount of time the username and password are being used and sent across the wire.
How many times do you want your username and password, SSN, or other sensitive data do you want being stored and transmitted? Do you want that on every request?
First of all, access tokens are typically validated by checking the digital signature, which does not require the receiving service to talk to the issuing server. The client gets an access token once and uses it until it expires.
But even if the token had to be checked against the database on every call (when using reference tokens for example), tokens are still preferred over sending username and password on each call. They remove the need for the client to keep the password in memory (or elsewhere), where it can easily be stolen.
(1) Access token is less sensitive than your password. Access tokens typically expire after a short time (this is a requirement in the Oauth threat model), whereas passwords tends to be long term. If somebody grabs your access token, there is limited damage they can do. If they grab your password, then there is a lot of damage that they can do. Especially if you use the same or related passwords on multiple sites.
(2) If the server implemented password verification securely, then they should be using a slow function like PBKDF2, bcrypt, or scrypt to validate your passwords. These functions are designed to be slow so that if somebody gets access to the database, they will not be able to reverse many passwords: see Our password hashing has no clothes. Given that password checking is supposed to be slow, we don't want to be doing it often! Validation of access tokens is much quicker however.
(3) The system that grants you access to a resource ("resource provider") might not be the same as the system that checks your identity ("identity provider"). For example, many websites including StackOverflow allow you go login with your gmail account. In this case, Google is the identity provider and StackOverflow is the resource provider. Would you really want to provide your gmail password to StackOverflow? I hope not.
I have some problems to understand how to secure REST API.
When a client sign up, the password is hashed and sent to the server through HTTPS.
Then, the server store hash(password+privatesalt).
When the client consumes a rest service, he creates the request and a signature HMAC-SHA1 with his own password (like here).
Server side, how to sign the request to compare with the client signature if the password is hash-salted in the database ?
I know the data appears in clear over the web, but I just want to authenticate the user.
You are right. If the password is stored hashed & salted on the server side, it is not possible to verify the HMAC computed on the request: a MAC required a shared secret between the client and the server.
Some solutions could be:
using a dedicated API key which is not the user password. As far as I know, this is the AWS choice. The password is used for administrative operation on the user account (e.g. changing the billing contact) and the API key is only used by the API client. In this case if this API key is compromised, it is relatively easy to revoke it and generate a new one with a more limited impact on the security.
using HTTPS with X509 client certificates. This is a more heavyweight solution and probably more complex to setup. However it is transparent for the API users since the authentication is moved to the transport layer of the protocol.
I am developing a web service and I need to send a username and password to the service in a GET method. Is it OK to send this information in the uri as long as it's going over a secure channel like ssl? In other words, can I have a uri that looks like /users/{username}/{cleartext_password}?
Edit: Sorry, I think I was unclear. The web service is essentially just a database of usernames and hashed passwords. Imagine a desktop application that keeps usernames and passwords in a remote database. The end user types their username and password into the application and the application accesses the web service to authenticate the user.
So, the application will need to send an end user's username and plaintext password to the service. The service will take the username and password and check that the username and the hash of the password match the username and hashed password in the database. The application itself will have to authenticate before it can access the service, but I am just wondering what is the best way to send the end user's username and password to the service for authenticating the end user. I don't to use a POST method because I am simply authenticating and therefore not changing the state of the server. Sorry for the confusion.
Do this.
Send a "key" and a "digest".
The "key" is equivalent to a username.
The "digest" is a SHA1 (or MD5) hash of the key, the URI and a "shared secret" or password.
When the server gets this, it computes it's own version of the digest, based on key, URI being requested and the "shared secret" or password. Failure to match digests is a 401 error response.
If it's going over a secure channel, there's no problem sending the username and password as cleartext. I'd just recommend against ever sending them as cleartext through an insecure channel and against sending them repeatedly for each request.
What you could do is first authenticate to the web service (send the username and password via ssl as cleartext) and get a token from the server that it will recognize. Then send that token with each subsequent request.
Generally speaking this is not a good idea... This data will be present in a number of log files, consequently the data could be visible to people who should not see it. At the very least you should hash or encrypt it before sending it if you can.
Here is a related discussion for a little more detail... Is an HTTPS query string secure?
SSL does encrypt the URI, but definitely take a look at some alternatives.
HTTP Basic Auth is nice and simple, and well supported by browsers, webservers, etc
It also won't end up in log files to the same degree as URIs
NB: It's just some plain-text HTTP Headers, so definitiely NOT recommended for non-SSL apps.
http://en.wikipedia.org/wiki/Basic_access_authentication