1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.shiro.web.filter;
21
22 import org.apache.shiro.web.util.WebUtils;
23
24 import javax.servlet.ServletRequest;
25 import javax.servlet.ServletResponse;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.List;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 public class InvalidRequestFilter extends AccessControlFilter {
44
45 private static final List<String> SEMICOLON = Collections.unmodifiableList(Arrays.asList(";", "%3b", "%3B"));
46
47 private static final List<String> BACKSLASH = Collections.unmodifiableList(Arrays.asList("\\", "%5c", "%5C"));
48
49 private boolean blockSemicolon = true;
50
51 private boolean blockBackslash = true;
52
53 private boolean blockNonAscii = true;
54
55 @Override
56 protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
57 String uri = WebUtils.toHttp(request).getRequestURI();
58 return !containsSemicolon(uri)
59 && !containsBackslash(uri)
60 && !containsNonAsciiCharacters(uri);
61 }
62
63 @Override
64 protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
65 WebUtils.toHttp(response).sendError(400, "Invalid request");
66 return false;
67 }
68
69 private boolean containsSemicolon(String uri) {
70 if (isBlockSemicolon()) {
71 return SEMICOLON.stream().anyMatch(uri::contains);
72 }
73 return false;
74 }
75
76 private boolean containsBackslash(String uri) {
77 if (isBlockBackslash()) {
78 return BACKSLASH.stream().anyMatch(uri::contains);
79 }
80 return false;
81 }
82
83 private boolean containsNonAsciiCharacters(String uri) {
84 if (isBlockNonAscii()) {
85 return !containsOnlyPrintableAsciiCharacters(uri);
86 }
87 return false;
88 }
89
90 private static boolean containsOnlyPrintableAsciiCharacters(String uri) {
91 int length = uri.length();
92 for (int i = 0; i < length; i++) {
93 char c = uri.charAt(i);
94 if (c < '\u0020' || c > '\u007e') {
95 return false;
96 }
97 }
98 return true;
99 }
100
101 public boolean isBlockSemicolon() {
102 return blockSemicolon;
103 }
104
105 public void setBlockSemicolon(boolean blockSemicolon) {
106 this.blockSemicolon = blockSemicolon;
107 }
108
109 public boolean isBlockBackslash() {
110 return blockBackslash;
111 }
112
113 public void setBlockBackslash(boolean blockBackslash) {
114 this.blockBackslash = blockBackslash;
115 }
116
117 public boolean isBlockNonAscii() {
118 return blockNonAscii;
119 }
120
121 public void setBlockNonAscii(boolean blockNonAscii) {
122 this.blockNonAscii = blockNonAscii;
123 }
124 }