Abstract:
- Using JWT instead of session is not a good idea in Web applications.
- Suitable for JWT usage scenarios.
Sorry, I fell for clickbait. I do not deny the value of JWT, but it is often misused.
What is the JWT
According to Wikipedia, a JSON WEB Token (JWT) is a JSON-based Token used to make a claim on the WEB. A JWT usually consists of three parts: header, payload, and signature.
The header specifies the signature algorithm used by the JWT:
header = '{"alg":"HS256","typ":"JWT"}'
Copy the code
HS256 indicates that hMAC-SHA256 is used to generate signatures.
The message body contains the intent of JWT:
Payload = '{"loggedInAs":"admin"," IAT ":1422779638}'// IAT specifies the token generation timeCopy the code
Unsigned tokens are concatenated from base64URL-encoded headers and message bodies (using “. Delimited), and the signature is computed using a private key:
key = 'secretkey'
unsignedToken = encodeBase64(header) + '.' + encodeBase64(payload)
signature = HMAC-SHA256(key, unsignedToken)
Copy the code
Finally, the base64URL-encoded signature is concatenated at the end of the unsigned token (again using “. Delimited) is JWT:
Token = encodeBase64(header) + '.' + encodeBase64(payload) + '.' + encodeBase64(signature) # Token looks like this: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh9.gzSraSYS8EXBxLN_oWnFSRgCzcmJmM jLiuyu5CSpyHICopy the code
JWT is often used as a resource to protect the server. The client usually sends JWT to the server through HTTP Authorization header, and the server calculates and verifies the signature with its own saved key to determine whether the JWT is trusted:
Authorization: Bearer eyJhbGci*... <snip>... *yu5CSpyHICopy the code
How could that be misused
In recent years, RESTful apis have become so popular that it seems natural to use HTTP headers to pass authentication tokens, while single-page applications (SPA) and the back-end separation architecture seem to be encouraging more and more WEB applications to abandon the age-old cookie-session authentication mechanism. Use JWT instead to manage user sessions. Supporters of the scheme argue that:
1. The scheme is easier to extend horizontally
In the cookie-session scheme, cookies contain only one session identifier, and user information, authorization list, and so on are stored in the server’s session. If all the authentication information in the session is stored in the JWT, there is no need for the session to exist on the server. When servers scale horizontally, there is no need to deal with session replication/sticky sessions or import external session storage.
From this point of view, this advantage does exist, but the reality is that external session storage schemes are quite mature (such as Redis), and session replication is not as troublesome as expected with the help of some frameworks (such as Spring-Session and Hazelcast). So unless you have very, very, very high traffic to your app, using cookie-session with external session storage is perfectly fine.
2. The solution protects against CSRF attacks
Cross-site request forgery (SEA-surf) is a typical attack that exploits cookie-session vulnerability. Here is an example of Spring-Security to interpret CSRF:
Suppose you often use bank.example.com to transfer money online. When you submit a transfer request, bank.example.com’s front end will submit an HTTP request:
POST/Transfer HTTP/1.1 Host: bank.example.com Cookie: JsessionID= randomId; Domain=bank.example.com; Secure; HttpOnly content-type: application/x - WWW - form - urlencoded amount = 100.00 & routingNumber = 1234 & account = 9876Copy the code
You avoid logging out of bank.example.com and then visit a malicious site whose HTML page contains a form like this:
< form action = "https://bank.example.com/transfer" method = "post" > < input type = "hidden" name = "amount" value = "100.00" / > <input type="hidden" name="routingNumber" value="evilsRoutingNumber"/> <input type="hidden" name="account" Value ="evilsAccountNumber"/> <input type="submit" value=" submit" /> </form>Copy the code
You’re hooked on “click and send”, and when you click the submit button you’ve already transferred $100 to the attacker’s account. In the real world, the attack may be more subtle, and pages from malicious sites may use Javascript to automate submission. Although there is no way for a malicious site to steal your session cookie (and thus impersonate you), your cookie will be sent automatically when a malicious site makes a request to bank.example.com.
Therefore, some argue that front-end code sending JWT to the server via HTTP headers (rather than automatically sending it via cookies) is effective in protecting CSRF. In this scenario, after authentication, the server code will return the JWT in the HTTP response header, and the front-end code stores the JWT in the Local Storage for future use, or the server directly stores the JWT HttpOnly=false in the cookie.
When the request is made to the server, the JWT is retrieved in Javascript (otherwise the front-end Javascript code has no right to get data from the cookie) and sent back to the server through the header for authentication. This does protect against CSRF because the code of a malicious site cannot obtain the JWT in cookie/Local Storage of Bank.example.com, but storing the JWT in cookie/Local Storage may allow another attack. We’ll discuss this in detail in a moment: cross-site scripting attack — XSS.
3. The scheme is safer
Since JWT requires a secret key and an algorithm that produces a token that looks unreadable, many people assume that the token is encrypted. However, the secret key and algorithm are actually used to generate the signature, and the token itself is not readable only because of base64URL encoding, which can be directly decoded, so if sensitive information is stored in JWT, it is less secure than cookie-session to put the data on the server.
In addition to these misconceptions, using JWT to manage sessions has the following disadvantages:
- More space taken up. If all types of information originally stored in the server session are stored in the JWT and stored in the client, the space occupied by the JWT may increase, and the space limit of cookies and other factors need to be considered. If stored in the Local Storage, XSS attacks may occur.
- It’s less safe. JWT is stored in Local Storage and sent to the server as an HTTP header using Javascript. Storing sensitive information in Local Storage is unsafe and vulnerable to cross-site script attacks. Cross-site script (XSS for short) is a kind of “HTML injection”. Since most of the attacked scripts are cross-domain, it is called “cross-domain script”. These scripts can steal cookies or Local Storage data. See this article for an explanation of how XSS attacks work.
- An issued token cannot be invalidated. All authentication information is in the JWT, and since there is no state on the server, there is no way to invalidate a JWT even if you know it has been stolen. Until JWT expires (and you absolutely should), there’s nothing you can do.
- Difficult to deal with data expiration. Similar to the previous article, JWT is a bit like a cache in that you can only live with “expired” data before it expires because you can’t invalidate issued tokens.
After reading this, you may realize that keeping JWT in Local Storage and using JWT to manage sessions is not a good idea. Is it possible to use JWT “correctly” to manage sessions? Such as:
- Instead of using Local Storage to store JWT, use cookies and set HttpOnly=true, which means that JWT can only be saved by the server and retrieved by automatically sent cookies to defend against XSS attacks
- Add a random value to the contents of the JWT as a CSRF token, which the server also stores in the cookie, but with HttpOnly=false, so that the front-end Javascript code can retrieve the CSRF token and pass it back as an HTTP header when requesting the API. During authentication, the server takes out the CSRF token from JWT and compares it with the CSRF token obtained from header to protect against CSRF attacks
- Considering the space limit of cookies (about 4K), only “sufficient” authentication information should be put in JWT as far as possible, and other information should be put in the database and obtained when needed. Meanwhile, the data expiration problem mentioned above should also be solved
This seems like a pretty good solution. Congratulations, you’ve reinvented cookie-session, maybe not as good as the existing implementation.
So what exactly can JWT be used for
My colleague once made a graphic explanation:
JWT (and indeed SAML) is best used in “invoicing,” or “signing.”
In office, have paper work between departments, organizations often need to take A head of department of “signature” or “sealed” to B department “use” or “visit” the corresponding resources, actually this kind of “leadership signature/stamp” is JWT, is A by the entity of A certain power “issued” “paper” and “empowerment”. Generally, this instrument is verifiable (the signature/seal of the leader can be verified, and difficult to imitate), and cannot be tampered with (the altered document is not accepted, unless the altered document is signed again for confirmation); In addition, such notes are generally used “once”. After accessing the corresponding resources, the notes are generally recovered by the resource holder for subsequent audit and traceability.
Two examples:
- Employee Li Lei needed to ask for leave for a day, so he filled in the leave application form. After li Lei got the signature of the leader in charge of the department, he gave the leave form to the HR department Han Meimei. After han Meimei confirmed that the signature of the leader was correct, she took back the leave form and made corresponding records in the company’s attendance sheet.
- Employees Li Lei and Han Meimei needed to use the company car for a day when they went out for work, so they filled in the car application form. After signing the form, Li Lei gave the application form to Lao Wang, the driver of the team, and took the car driven by Lao Wang to go out for business. Meanwhile, Lao Wang took back the car application form and filed it.
In the above two examples, “application form for leave” and “application form for car use” are payload in JWT, the signature of the leader is the digital signature after Base64, and the leader is issuer. “Han Meimei from HR Department” and “Driver Lao Wang” are the audiences of JWT. The audience needs to verify whether the leader’s signature is valid. After the verification, the audience gives corresponding permissions to the resources requested in the payload and takes back the JWT.
In a system integration scenario, JWT is more suitable for one-shot certification:
Hello, service B, service A told me that I can operate <JWT content >, this is my credential (namely JWT).
In this case, service A is responsible for authenticating the user (equivalent to the supervisor approving the leave in the example above) and issuing A JWT with A short expiration time to the browser (equivalent to the leave in the example above). The browser (equivalent to the employee requesting the leave in the example above) carries the JWT with the request to service B. Then service B (equivalent to the HR employee in the example above) can verify the JWT to determine whether the user has the right to perform the operation. Thus, service B becomes a secure stateless service.
conclusion
- In Web applications, don’t use JWT as a session. In most cases, the traditional cookie-session mechanism works better
- JWT is suitable for one-time command authentication. Issuing a JWT with a very short validity period is very dangerous even if exposed. Since new JWT is generated every time, there is no need to save the JWT to achieve true statelessness.
reference
Auth0.com/blog/ten-th…
Auth0.com/docs/securi…
Cryto.net/~joepie91/b…
For more insights, please follow our wechat official account: Sitvolk