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