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