View Javadoc
1   package com.jsql.util;
2   
3   import com.jsql.model.InjectionModel;
4   import org.apache.commons.lang3.StringUtils;
5   import org.apache.logging.log4j.LogManager;
6   import org.apache.logging.log4j.Logger;
7   import org.jsoup.Jsoup;
8   
9   import java.net.http.HttpRequest.Builder;
10  import java.util.AbstractMap.SimpleEntry;
11  import java.util.*;
12  import java.util.stream.Stream;
13  
14  public class CsrfUtil {
15      
16      /**
17       * Log4j logger sent to view.
18       */
19      private static final Logger LOGGER = LogManager.getRootLogger();
20  
21      private SimpleEntry<String, String> tokenCsrf = null;
22      
23      private static final String SET_COOKIE_RESPONSE = "set-cookie";
24      private static final String INPUT_ATTR_VALUE = "value";
25      private static final String MSG_ENABLE_CSRF = "Try with option CSRF processing enabled in preferences";
26  
27      private final InjectionModel injectionModel;
28      
29      public CsrfUtil(InjectionModel injectionModel) {
30          this.injectionModel = injectionModel;
31      }
32  
33      public void parseForCsrfToken(String pageSource, Map<String, String> headers) {
34          
35          this.parseCsrfFromCookie(headers);
36          this.parseCsrfFromHtml(pageSource);
37      }
38  
39      private void parseCsrfFromHtml(String pageSource) {
40  
41          // Change immutable list to mutable for adding user tag
42          List<String> tags = new ArrayList<>(
43              Arrays.asList(
44                  "[name=_csrf]",
45                  "[name=_token]",
46                  "[name=csrf-token]",
47                  "[name=_csrf_header]",
48                  "[name=csrf_token]",
49                  "[name=csrfToken]",
50                  "[name=user_token]",
51                  "[name=csrfmiddlewaretoken]",
52                  "[name=form_build_id]"
53              )
54          );
55          
56          if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isCsrfUserTag()) {
57              tags.add(
58                  String.format(
59                      "[name='%s']",
60                      this.injectionModel.getMediatorUtils().getPreferencesUtil().csrfUserTag()
61                  )
62              );
63          }
64          
65          Optional<SimpleEntry<String, String>> optionalTokenCsrf = Jsoup
66              .parse(pageSource)
67              .select("input")
68              .select(
69                  String.join(",", tags)
70              )
71              .stream()
72              .findFirst()
73              .map(input ->
74                  new SimpleEntry<>(
75                      input.attr("name"),
76                      input.attr(INPUT_ATTR_VALUE)
77                  )
78              );
79          
80          if (optionalTokenCsrf.isPresent()) {
81              
82              SimpleEntry<String, String> tokenCsrfFound = optionalTokenCsrf.get();
83              
84              LOGGER.log(
85                  LogLevelUtil.CONSOLE_INFORM,
86                  "Found Csrf token from HTML body: {}={}",
87                  tokenCsrfFound::getKey,
88                  tokenCsrfFound::getValue
89              );
90              
91              if (
92                  !this.injectionModel.getMediatorUtils().getPreferencesUtil().isNotProcessingCookies()
93                  && this.injectionModel.getMediatorUtils().getPreferencesUtil().isProcessingCsrf()
94              ) {
95                  this.tokenCsrf = tokenCsrfFound;
96                  LOGGER.log(
97                      LogLevelUtil.CONSOLE_SUCCESS,
98                      "Csrf token added to query and header: {}",
99                      tokenCsrfFound::getValue
100                 );
101             } else {
102                 LOGGER.log(LogLevelUtil.CONSOLE_INFORM, MSG_ENABLE_CSRF);
103             }
104         }
105     }
106 
107     private void parseCsrfFromCookie(Map<String, String> mapResponse) {
108         
109         Optional<SimpleEntry<String, String>> optionalCookieCsrf = Optional.empty();
110         
111         if (mapResponse.containsKey(SET_COOKIE_RESPONSE)) {
112             
113             // Spring: Cookie XSRF-TOKEN => Header X-XSRF-TOKEN, GET/POST parameter _csrf
114             // Laravel, Zend, Symfony
115             
116             String[] cookieValues = StringUtils.split(mapResponse.get(SET_COOKIE_RESPONSE), ";");
117             
118             optionalCookieCsrf = Stream.of(cookieValues)
119                 .filter(cookie -> cookie.trim().toLowerCase().startsWith("xsrf-token"))
120                 .map(cookie -> {
121                     
122                     String[] cookieEntry = StringUtils.split(cookie, "=");
123 
124                     return new SimpleEntry<>(
125                         cookieEntry[0].trim(),
126                         cookieEntry[1].trim()
127                     );
128                 })
129                 .findFirst();
130         }
131         
132         if (optionalCookieCsrf.isPresent()) {
133             
134             SimpleEntry<String, String> cookieCsrf = optionalCookieCsrf.get();
135             
136             LOGGER.log(
137                 LogLevelUtil.CONSOLE_ERROR,
138                 "Found CSRF token from Cookie: {}={}",
139                 cookieCsrf::getKey,
140                 cookieCsrf::getValue
141             );
142             
143             SimpleEntry<String, String> headerCsrf = new SimpleEntry<>(
144                 cookieCsrf.getKey(),
145                 cookieCsrf.getValue()
146             );
147             
148             if (
149                 !this.injectionModel.getMediatorUtils().getPreferencesUtil().isNotProcessingCookies()
150                 && this.injectionModel.getMediatorUtils().getPreferencesUtil().isProcessingCsrf()
151             ) {
152                 this.tokenCsrf = headerCsrf;
153             } else {
154                 LOGGER.log(LogLevelUtil.CONSOLE_INFORM, MSG_ENABLE_CSRF);
155             }
156         }
157     }
158 
159     public void addHeaderToken(Builder httpRequest) {
160         
161         if (this.tokenCsrf == null) {
162              return;
163         }
164 
165         httpRequest.setHeader("X-XSRF-TOKEN", this.tokenCsrf.getValue());
166         httpRequest.setHeader("X-CSRF-TOKEN", this.tokenCsrf.getValue());
167         
168         if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isCsrfUserTag()) {
169             httpRequest.setHeader(
170                 this.injectionModel.getMediatorUtils().getPreferencesUtil().csrfUserTagOutput(),
171                 this.tokenCsrf.getValue()
172             );
173         }
174     }
175 
176     public void addRequestToken(StringBuilder httpRequest) {
177 
178         if (this.tokenCsrf == null) {
179             return;
180         }
181 
182         httpRequest.append(
183             String.format(
184                 "%s=%s&",
185                 this.tokenCsrf.getKey(),
186                 this.tokenCsrf.getValue()
187             )
188         );
189         
190         httpRequest.append(
191             String.format(
192                 "_csrf=%s&",
193                 this.tokenCsrf.getValue()
194             )
195         );
196         
197         if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isCsrfUserTag()) {
198             httpRequest.append(
199                 String.format(
200                     "%s=%s&",
201                     this.injectionModel.getMediatorUtils().getPreferencesUtil().csrfUserTagOutput(),
202                     this.tokenCsrf.getValue()
203                 )
204             );
205         }
206     }
207     
208     public String addQueryStringToken(String urlInjection) {
209         
210         String urlInjectionFixed = urlInjection;
211 
212         if (this.tokenCsrf == null) {
213             return urlInjectionFixed;
214         }
215 
216         urlInjectionFixed += String.format(
217             "&%s=%s",
218             this.tokenCsrf.getKey(),
219             this.tokenCsrf.getValue()
220         );
221         
222         urlInjectionFixed += String.format(
223             "&_csrf=%s",
224             this.tokenCsrf.getValue()
225         );
226         
227         if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isCsrfUserTag()) {
228             urlInjectionFixed += String.format(
229                 "&%s=%s",
230                 this.injectionModel.getMediatorUtils().getPreferencesUtil().csrfUserTagOutput(),
231                 this.tokenCsrf.getValue()
232             );
233         }
234         
235         return urlInjectionFixed;
236     }
237     
238     
239     // Getter / Setter
240 
241     public boolean isCsrf() {
242         return this.tokenCsrf != null;
243     }
244 
245     public SimpleEntry<String, String> getTokenCsrf() {
246         return this.tokenCsrf;
247     }
248 
249     public void setTokenCsrf(SimpleEntry<String, String> tokenCsrf) {
250         this.tokenCsrf = tokenCsrf;
251     }
252 }