1313import javax .servlet .http .HttpServletRequest ;
1414import javax .servlet .http .HttpServletResponse ;
1515import javax .servlet .http .HttpSession ;
16+ import java .net .URI ;
17+ import java .net .URISyntaxException ;
18+ import java .nio .charset .StandardCharsets ;
19+ import java .security .MessageDigest ;
1620import java .util .HashMap ;
1721import java .util .Map ;
1822import java .util .UUID ;
@@ -80,12 +84,12 @@ public Map<String, Object> getCsrfToken(HttpSession session, Model model) {
8084
8185 @ GetMapping ("/safe1" )
8286 @ ResponseBody
83- public Map <String , Object > safe1 (@ RequestParam ("receiver" ) String receiver ,@ RequestParam ("amount" ) String amount ,@ AuthenticationPrincipal UserDetails userDetails ,@ RequestParam ("csrfToken" ) String csrfToken ,HttpSession session ) {
87+ public Map <String , Object > safe1 (@ RequestParam ("receiver" ) String receiver , @ RequestParam ("amount" ) String amount , @ AuthenticationPrincipal UserDetails userDetails , @ RequestParam (value = "csrfToken" , required = false ) String csrfToken , HttpSession session ) {
8488 String currentUser = userDetails .getUsername ();
8589
8690 String sessionToken = (String ) session .getAttribute ("csrfToken" );
8791 Map <String , Object > result = new HashMap <>();
88- if (!csrfToken . equals ( sessionToken )) {
92+ if (!constantTimeEquals ( csrfToken , sessionToken )) {
8993 result .put ("success" , false );
9094 result .put ("message" , "Token失效!" );
9195 return result ;
@@ -102,10 +106,13 @@ public Map<String, Object> safe1(@RequestParam("receiver") String receiver,@Requ
102106 public Map <String , Object > safe2 (HttpServletRequest request , @ RequestParam ("receiver" ) String receiver , @ RequestParam ("amount" ) String amount , @ AuthenticationPrincipal UserDetails userDetails , HttpSession session ) {
103107 String currentUser = userDetails .getUsername ();
104108 Map <String , Object > result = new HashMap <>();
105- String referer = request .getHeader ("referer" );
106- if (referer == null || !referer .startsWith ("http://127.0.0.1" )) {
109+ String originOrReferer = request .getHeader ("Origin" );
110+ if (originOrReferer == null ) {
111+ originOrReferer = request .getHeader ("Referer" );
112+ }
113+ if (!isTrustedSameOrigin (request , originOrReferer )) {
107114 result .put ("success" , false );
108- result .put ("message" , "referer无效 !" );
115+ result .put ("message" , "Origin/Referer无效 !" );
109116 return result ;
110117 }
111118 result .put ("currentUser" , currentUser );
@@ -114,4 +121,40 @@ public Map<String, Object> safe2(HttpServletRequest request, @RequestParam("rece
114121 return result ;
115122 }
116123
124+ private boolean constantTimeEquals (String requestToken , String sessionToken ) {
125+ if (requestToken == null || sessionToken == null ) {
126+ return false ;
127+ }
128+ return MessageDigest .isEqual (
129+ requestToken .getBytes (StandardCharsets .UTF_8 ),
130+ sessionToken .getBytes (StandardCharsets .UTF_8 )
131+ );
132+ }
133+
134+ private boolean isTrustedSameOrigin (HttpServletRequest request , String originOrReferer ) {
135+ if (originOrReferer == null ) {
136+ return false ;
137+ }
138+ try {
139+ URI uri = new URI (originOrReferer );
140+ String expectedScheme = request .getScheme ();
141+ String expectedHost = request .getServerName ();
142+ int expectedPort = request .getServerPort ();
143+ int actualPort = uri .getPort () == -1 ? defaultPort (uri .getScheme ()) : uri .getPort ();
144+
145+ return expectedScheme .equalsIgnoreCase (uri .getScheme ())
146+ && expectedHost .equalsIgnoreCase (uri .getHost ())
147+ && expectedPort == actualPort ;
148+ } catch (URISyntaxException e ) {
149+ return false ;
150+ }
151+ }
152+
153+ private int defaultPort (String scheme ) {
154+ if ("https" .equalsIgnoreCase (scheme )) {
155+ return 443 ;
156+ }
157+ return 80 ;
158+ }
159+
117160}
0 commit comments