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
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
101
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
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 }