Previously, a small partner said that it would be better to write a Filter intercept request for Spring Security, which is so troublesome.
Writing on your own is certainly possible, but in most cases, everyone is not a professional Web security engineer, so the problem is just certification and authorization. Once these two issues are addressed, it seems that the system is safe.
Not really!
A variety of Web attacks occur every day, such as fixed session attacks, csrf attacks, and so on. If you do not understand these attacks, then the system will certainly not be able to defend against them.
The advantage of using Spring Security is that you don't have to worry about these attacks even if you don't know them, because Spring Security has already helped you defend against them.
We often say that compared to Shiro, Spring Security is more heavyweight, heavyweight has the advantages of heavyweight, such as full functionality and more complete safety management.With Spring Security, you don't know how secure your system is!
Today, I'm going to talk to you about the firewall mechanism that comes with Spring Security.
This is the fifteenth in the Spring Security series. Reading the previous articles in this series will help you better understand this:
- Dig a big hole and start Spring Security!
- Pingo takes you to Spring Security by hand. Don't ask me how to decrypt the password anymore
- Hand-on instructions for customizing form logins in Spring Security
- Spring Security does front-end separation, let's not do page jumps!Unified JSON Interaction
- Authorization in Spring Security was so simple
- How does Spring Security store user data in the database?
- Spring Security+Spring Data Jpa join forces, so security management is only simpler!
- Spring Boot + Spring Security for automatic login
- Spring Boot automatic login, how to control security risk?
- Where is Spring Security better than Shiro in a microservice project?
- Two ways SpringSecurity customizes authentication logic (advanced gameplay)
- How can I quickly view information like login user IP address in Spring Security?
- Spring Security automatically kicks off the previous logged-in user, a configuration is complete!
- Spring Boot + Vue front-end split project, how to kick the logged-in user?
Okay, no more nonsense. Let's take a look at the article.
1.HttpFirewall
An HttpFirewall is provided in Spring Security, and you know by name that it is a request firewall that automatically handles some illegal requests.
HttpFirewall currently has two implementation classes:
One is the strict mode of firewall settings, and the other is the default firewall settings.
DefaultHttpFirewall's limitations are less restrictive than StrictHttpFirewall's, and of course it means less secure than StrictHttpFirewall.
StrictHttpFirewall is used by default in Spring Security.
2. PROTECTIVE MEASURES
So what does StrictHttpFirewall do to protect our apps?Let's look one by one.
2.1 Allow only whitelist methods
First, only whitelist methods are allowed for the requested method, that is, not all HTTP request methods can be executed.
This can be seen from the source code of StrictHttpFirewall:
public class StrictHttpFirewall implements HttpFirewall { private Set<string> allowedHttpMethods = createDefaultAllowedHttpMethods(); private static Set<string> createDefaultAllowedHttpMethods() { Set<string> result = new HashSet<>(); result.add(HttpMethod.DELETE.name()); result.add(HttpMethod.GET.name()); result.add(HttpMethod.HEAD.name()); result.add(HttpMethod.OPTIONS.name()); result.add(HttpMethod.PATCH.name()); result.add(HttpMethod.POST.name()); result.add(HttpMethod.PUT.name()); return result; } private void rejectForbiddenHttpMethod(HttpServletRequest request) { if (this.allowedHttpMethods == ALLOW_ANY_HTTP_METHOD) { return; } if (!this.allowedHttpMethods.contains(request.getMethod())) { throw new RequestRejectedException("The request was rejected because the HTTP method \"" + request.getMethod() + "\" was not included within the whitelist " + this.allowedHttpMethods); } } }
As we can see from this code, your HTTP request method must be one of DELETE, GET, HEAD, OPTIONS, PATCH, POST, and PUT in order for the request to be sent successfully, otherwise the RequestRejectedException exception will be thrown.
So what if you want to send other HTTP request methods, such as TRACE?We just need to provide a new instance of StrictHttpFirewall on our own, as follows:
@Bean HttpFirewall httpFirewall() { StrictHttpFirewall firewall = new StrictHttpFirewall(); firewall.setUnsafeAllowAnyHttpMethod(true); return firewall; }
The setUnsafe AllowAnyHttpMethod method means that no HTTP request method checking is done, that is, any method can be used.Alternatively, the setAllowedHttpMethods method can be used to redefine the available methods.
2.2 Request address cannot have semicolon
I don't know if you've tried it or not. If you use Spring Security, the request address can't be; if the request address has; it will automatically jump to the following page:
As you can see, the prompt on the page already says, because your request address contains;, the request failed.
When will the request be included in the address; and?I don't know if your little buddies noticed when they used Shiro that if you disabled cookies, jsessionid would appear in the address bar, like the following:
http://localhost:8080/hello;jsessionid=xx
This method of passing jsessionid is actually very unsafe (the article that follows Songo will talk about it in detail), so it is disabled by default in Spring Security.
Of course, if you want the address bar to be allowed to appear, you can set it as follows:
@Bean HttpFirewall httpFirewall() { StrictHttpFirewall firewall = new StrictHttpFirewall(); firewall.setAllowSemicolon(true); return firewall; }
After the setup is complete, go to the same interface again, you can see that although there is still an error at this time, the error is 404, not the one that was not allowed at the beginning; the error is wrong.
Note that in the URL address,; after encoding is either%3b or%3B, so either%3b or%3B cannot appear in the address
Off-topic topicStarting with Spring 3.2, some of your little friends may not know or have not used it, a new way of passing @MatrixVariable has been introduced.
@MatrixVariable is a feature introduced in Spring 3.2 that extends the format in which parameters are requested to be passed so that they can be used between them; separated, this way of passing parameters really doesn't tell which pot.Because Spring Security prohibits this by default, in general, if you need to mark parameters with @MatrixVariable, you will have to pass extra in Spring Security.
Next, I'll show you a simple example of how @MatrixVariable works.
Let's create a new / hello method:
@RequestMapping(value = "/hello/") public void hello(@PathVariable Integer id,@MatrixVariable String name) { System.out.println("id = " + id); System.out.println("name = " + name); }
We also need to configure SpringMVC so that it does not get removed automatically:
@Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { @Override protected void configurePathMatch(PathMatchConfigurer configurer) { UrlPathHelper urlPathHelper = new UrlPathHelper(); urlPathHelper.setRemoveSemicolonContent(false); configurer.setUrlPathHelper(urlPathHelper); } }
Then start the project (note that allowed URL s are also configured in Spring Security;), and the browser sends the following request:
http://localhost:8080/hello/123;name=javaboy
The console prints the following information:
id = 123 name = javaboy
As you can see, the @MatrixVariable annotation is already in effect.
2.3 Must be a standardized URL
Request address must be a standardized URL.
What is a standardized URL?Standardized URLs are judged from four main aspects, let's look at the source code:
StrictHttpFirewall#isNormalized:
private static boolean isNormalized(HttpServletRequest request) { if (!isNormalized(request.getRequestURI())) { return false; } if (!isNormalized(request.getContextPath())) { return false; } if (!isNormalized(request.getServletPath())) { return false; } if (!isNormalized(request.getPathInfo())) { return false; } return true; }
getRequestURI is a character other than the request protocol; getContextPath is the get context path, which corresponds to the name of the project; getServletPath is the requested servlet path; getPathInfo is the rest after the contextPath and servletPath.
None of these four paths can contain the following string:
"./", "/../" or "/."
2.4 Must be printable ASCII characters
If the request address contains non-printable ASCII characters, the request will be rejected. We can see from the source code that:
StrictHttpFirewall#containsOnlyPrintableAsciiCharacters
private static boolean containsOnlyPrintableAsciiCharacters(String uri) { int length = uri.length(); for (int i = 0; i < length; i++) { char c = uri.charAt(i); if (c < '\u0020' || c > '\u007e') { return false; } } return true; }
2.5 Slash not allowed
If a double slash appears in the request address, the request will also be rejected.After encoding with a URL address, the double slash // is%2F%2F, where F case does not matter, so'%2f%2f','%2f%2F','%2F%2f','%2F%2F'and'%2F%2F' can also not appear in the request address.
If you want// to appear in the request address, you can configure it as follows:
@Bean HttpFirewall httpFirewall() { StrictHttpFirewall firewall = new StrictHttpFirewall(); firewall.setAllowUrlEncodedDoubleSlash(true); return firewall; }
2.6% Not allowed
If the request address appears, the request will also be rejected.The URL encoded%25, so%25 cannot appear in the URL address.
If you want the request address to appear, you can modify it as follows:
@Bean HttpFirewall httpFirewall() { StrictHttpFirewall firewall = new StrictHttpFirewall(); firewall.setAllowUrlEncodedPercent(true); return firewall; }
2.7 Forward and backward slashes are not allowed
If the request address contains slash-encoded characters%2F or%2f, the request will be rejected.
If the request address contains backslash\ or backslash encoded characters%5C or%5c, the request will be rejected.
If you want to remove the above two restrictions, you can configure them as follows:
@Bean HttpFirewall httpFirewall() { StrictHttpFirewall firewall = new StrictHttpFirewall(); firewall.setAllowBackSlash(true); firewall.setAllowUrlEncodedSlash(true); return firewall; }
2.8. Not allowed
If the.Encoded characters%2e,%2E exist in the request address, the request will be rejected.
If you need support, configure it as follows:
@Bean HttpFirewall httpFirewall() { StrictHttpFirewall firewall = new StrictHttpFirewall(); firewall.setAllowUrlEncodedPeriod(true); return firewall; }
2.9 Summary
It is important to emphasize that the restrictions mentioned above are restrictions on the request URI of the request, not the request parameters.For example, the format of your request is:
http://localhost:8080/hello?param=aa%2ebb
So the limitations in subsection 2.7 don't matter to you.
This is easy to see from the StrictHttpFirewall source code:
public class StrictHttpFirewall implements HttpFirewall { @Override public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException { rejectForbiddenHttpMethod(request); rejectedBlacklistedUrls(request); rejectedUntrustedHosts(request); if (!isNormalized(request)) { throw new RequestRejectedException("The request was rejected because the URL was not normalized."); } String requestUri = request.getRequestURI(); if (!containsOnlyPrintableAsciiCharacters(requestUri)) { throw new RequestRejectedException("The requestURI was rejected because it can only contain printable ASCII characters."); } return new FirewalledRequest(request) { @Override public void reset() { } }; } private void rejectedBlacklistedUrls(HttpServletRequest request) { for (String forbidden : this.encodedUrlBlacklist) { if (encodedUrlContains(request, forbidden)) { throw new RequestRejectedException("The request was rejected because the URL contained a potentially malicious String \"" + forbidden + "\""); } } for (String forbidden : this.decodedUrlBlacklist) { if (decodedUrlContains(request, forbidden)) { throw new RequestRejectedException("The request was rejected because the URL contained a potentially malicious String \"" + forbidden + "\""); } } } private static boolean encodedUrlContains(HttpServletRequest request, String value) { if (valueContains(request.getContextPath(), value)) { return true; } return valueContains(request.getRequestURI(), value); } private static boolean decodedUrlContains(HttpServletRequest request, String value) { if (valueContains(request.getServletPath(), value)) { return true; } if (valueContains(request.getPathInfo(), value)) { return true; } return false; } private static boolean valueContains(String value, String contains) { return value != null && value.contains(contains); } }
The rejectedBlacklistedUrls method checks URL s, and the logic is simple, so I won't go into that again.
Note: Although we can manually modify these restrictions in Spring Security, Pingo does not recommend that you make any changes. Each restriction has its own reason, and every release of a restriction presents an unknown security risk.Later, when Songgo shares security attacks on the Web with you, it will also mention the role of these restrictions again, so keep your little buddies concerned.
3. Summary
Surprisingly?Spring Security has done so much for you!Just the chicken soup:
>Your so-called years are quiet, but someone is carrying your weight.
Okay, I don't know if you have GET?If there are gains, remember to take a look at the encouragement Panasonic Oh~ </string></string></string>