CsrfUtil.java

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 1 1. parseForCsrfToken : removed call to com/jsql/util/CsrfUtil::parseCsrfFromCookie → NO_COVERAGE
        this.parseCsrfFromCookie(headers);
32 1 1. parseForCsrfToken : removed call to com/jsql/util/CsrfUtil::parseCsrfFromHtml → NO_COVERAGE
        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 1 1. parseCsrfFromHtml : negated conditional → NO_COVERAGE
        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 1 1. lambda$parseCsrfFromHtml$0 : replaced return value with null for com/jsql/util/CsrfUtil::lambda$parseCsrfFromHtml$0 → NO_COVERAGE
                new SimpleEntry<>(
67
                    input.attr("name"),
68
                    input.attr(CsrfUtil.INPUT_ATTR_VALUE)
69
                )
70
            );
71
        
72 1 1. parseCsrfFromHtml : negated conditional → NO_COVERAGE
        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 1 1. parseCsrfFromHtml : negated conditional → NO_COVERAGE
                !this.injectionModel.getMediatorUtils().getPreferencesUtil().isNotProcessingCookies()
82 1 1. parseCsrfFromHtml : negated conditional → NO_COVERAGE
                && 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 1 1. parseCsrfFromCookie : negated conditional → NO_COVERAGE
        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 2 1. lambda$parseCsrfFromCookie$1 : replaced boolean return with true for com/jsql/util/CsrfUtil::lambda$parseCsrfFromCookie$1 → NO_COVERAGE
2. lambda$parseCsrfFromCookie$1 : replaced boolean return with false for com/jsql/util/CsrfUtil::lambda$parseCsrfFromCookie$1 → NO_COVERAGE
                .filter(cookie -> cookie.trim().toLowerCase().startsWith("xsrf-token"))
105
                .map(cookie -> {
106
                    String[] cookieEntry = StringUtils.split(cookie, "=");
107 1 1. lambda$parseCsrfFromCookie$2 : replaced return value with null for com/jsql/util/CsrfUtil::lambda$parseCsrfFromCookie$2 → NO_COVERAGE
                    return new SimpleEntry<>(
108
                        cookieEntry[0].trim(),
109
                        cookieEntry[1].trim()
110
                    );
111
                })
112
                .findFirst();
113
        }
114
        
115 1 1. parseCsrfFromCookie : negated conditional → NO_COVERAGE
        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 1 1. parseCsrfFromCookie : negated conditional → NO_COVERAGE
                !this.injectionModel.getMediatorUtils().getPreferencesUtil().isNotProcessingCookies()
129 1 1. parseCsrfFromCookie : negated conditional → NO_COVERAGE
                && 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 1 1. addHeaderToken : negated conditional → NO_COVERAGE
        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 1 1. addHeaderToken : negated conditional → NO_COVERAGE
        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 1 1. addRequestToken : negated conditional → NO_COVERAGE
        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 1 1. addRequestToken : negated conditional → NO_COVERAGE
        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 1 1. addQueryStringToken : negated conditional → NO_COVERAGE
        if (this.tokenCsrf == null) {
185 1 1. addQueryStringToken : replaced return value with "" for com/jsql/util/CsrfUtil::addQueryStringToken → NO_COVERAGE
            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 1 1. addQueryStringToken : negated conditional → NO_COVERAGE
        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 1 1. addQueryStringToken : replaced return value with "" for com/jsql/util/CsrfUtil::addQueryStringToken → NO_COVERAGE
        return urlInjectionFixed;
204
    }
205
    
206
    
207
    // Getter / Setter
208
209
    public boolean isCsrf() {
210 2 1. isCsrf : replaced boolean return with true for com/jsql/util/CsrfUtil::isCsrf → NO_COVERAGE
2. isCsrf : negated conditional → NO_COVERAGE
        return this.tokenCsrf != null;
211
    }
212
213
    public SimpleEntry<String, String> getTokenCsrf() {
214 1 1. getTokenCsrf : replaced return value with null for com/jsql/util/CsrfUtil::getTokenCsrf → NO_COVERAGE
        return this.tokenCsrf;
215
    }
216
217
    public void setTokenCsrf(SimpleEntry<String, String> tokenCsrf) {
218
        this.tokenCsrf = tokenCsrf;
219
    }
220
}

Mutations

31

1.1
Location : parseForCsrfToken
Killed by : none
removed call to com/jsql/util/CsrfUtil::parseCsrfFromCookie → NO_COVERAGE

32

1.1
Location : parseForCsrfToken
Killed by : none
removed call to com/jsql/util/CsrfUtil::parseCsrfFromHtml → NO_COVERAGE

51

1.1
Location : parseCsrfFromHtml
Killed by : none
negated conditional → NO_COVERAGE

66

1.1
Location : lambda$parseCsrfFromHtml$0
Killed by : none
replaced return value with null for com/jsql/util/CsrfUtil::lambda$parseCsrfFromHtml$0 → NO_COVERAGE

72

1.1
Location : parseCsrfFromHtml
Killed by : none
negated conditional → NO_COVERAGE

81

1.1
Location : parseCsrfFromHtml
Killed by : none
negated conditional → NO_COVERAGE

82

1.1
Location : parseCsrfFromHtml
Killed by : none
negated conditional → NO_COVERAGE

99

1.1
Location : parseCsrfFromCookie
Killed by : none
negated conditional → NO_COVERAGE

104

1.1
Location : lambda$parseCsrfFromCookie$1
Killed by : none
replaced boolean return with true for com/jsql/util/CsrfUtil::lambda$parseCsrfFromCookie$1 → NO_COVERAGE

2.2
Location : lambda$parseCsrfFromCookie$1
Killed by : none
replaced boolean return with false for com/jsql/util/CsrfUtil::lambda$parseCsrfFromCookie$1 → NO_COVERAGE

107

1.1
Location : lambda$parseCsrfFromCookie$2
Killed by : none
replaced return value with null for com/jsql/util/CsrfUtil::lambda$parseCsrfFromCookie$2 → NO_COVERAGE

115

1.1
Location : parseCsrfFromCookie
Killed by : none
negated conditional → NO_COVERAGE

128

1.1
Location : parseCsrfFromCookie
Killed by : none
negated conditional → NO_COVERAGE

129

1.1
Location : parseCsrfFromCookie
Killed by : none
negated conditional → NO_COVERAGE

139

1.1
Location : addHeaderToken
Killed by : none
negated conditional → NO_COVERAGE

146

1.1
Location : addHeaderToken
Killed by : none
negated conditional → NO_COVERAGE

155

1.1
Location : addRequestToken
Killed by : none
negated conditional → NO_COVERAGE

171

1.1
Location : addRequestToken
Killed by : none
negated conditional → NO_COVERAGE

184

1.1
Location : addQueryStringToken
Killed by : none
negated conditional → NO_COVERAGE

185

1.1
Location : addQueryStringToken
Killed by : none
replaced return value with "" for com/jsql/util/CsrfUtil::addQueryStringToken → NO_COVERAGE

196

1.1
Location : addQueryStringToken
Killed by : none
negated conditional → NO_COVERAGE

203

1.1
Location : addQueryStringToken
Killed by : none
replaced return value with "" for com/jsql/util/CsrfUtil::addQueryStringToken → NO_COVERAGE

210

1.1
Location : isCsrf
Killed by : none
replaced boolean return with true for com/jsql/util/CsrfUtil::isCsrf → NO_COVERAGE

2.2
Location : isCsrf
Killed by : none
negated conditional → NO_COVERAGE

214

1.1
Location : getTokenCsrf
Killed by : none
replaced return value with null for com/jsql/util/CsrfUtil::getTokenCsrf → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.19.1