Skip to content

Commit f78f727

Browse files
committed
pscanrules: Charset Mismatch add example alerts
- CHANGELOG > Add note. - CharsetMismatchScanRule > Add example alerts, adjust handling, some minor related clean code changes. Drop alert related to "older clients". - CharsetMismatchScanRuleUnitTest > Add test to assert the example details, use parameterized case where practical. - Messages.properties > Clarify one of the descriptions. - Help > Drop details related to "older clients" alert. Signed-off-by: kingthorin <[email protected]>
1 parent d387303 commit f78f727

File tree

5 files changed

+106
-183
lines changed

5 files changed

+106
-183
lines changed

addOns/pscanrules/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66
## Unreleased
77
### Added
88
- The Reverse Tabnabbing and Retrieved from Cache scan rules now have CWE references.
9+
- The Charset Mismatch scan rule now includes example alert functionality for documentation generation purposes (Issue 6119) and alert references (Issue 7100).
10+
11+
### Removed
12+
- The Charset Mismatch scan rule no longer produces an alert with regard to META content-type and older clients.
913

1014
## [65] - 2025-06-20
1115
### Added

addOns/pscanrules/src/main/java/org/zaproxy/zap/extension/pscanrules/CharsetMismatchScanRule.java

Lines changed: 62 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020
package org.zaproxy.zap.extension.pscanrules;
2121

22+
import java.nio.charset.StandardCharsets;
2223
import java.util.Collections;
2324
import java.util.HashMap;
2425
import java.util.List;
@@ -47,6 +48,8 @@ public class CharsetMismatchScanRule extends PluginPassiveScanner
4748
/** Prefix for internationalized messages used by this rule */
4849
private static final String MESSAGE_PREFIX = "pscanrules.charsetmismatch.";
4950

51+
private static final int PLUGIN_ID = 90011;
52+
5053
private static final Map<String, String> ALERT_TAGS;
5154

5255
static {
@@ -56,12 +59,21 @@ public class CharsetMismatchScanRule extends PluginPassiveScanner
5659
ALERT_TAGS = Collections.unmodifiableMap(alertTags);
5760
}
5861

59-
private static enum MismatchType {
60-
NO_MISMATCH_METACONTENTTYPE_MISSING,
61-
HEADER_METACONTENTYPE_MISMATCH,
62-
HEADER_METACHARSET_MISMATCH,
63-
METACONTENTTYPE_METACHARSET_MISMATCH,
64-
XML_MISMATCH
62+
private enum MismatchType {
63+
HEADER_METACONTENTYPE_MISMATCH("-1"),
64+
HEADER_METACHARSET_MISMATCH("-2"),
65+
METACONTENTTYPE_METACHARSET_MISMATCH("-3"),
66+
XML_MISMATCH("-4");
67+
68+
private final String alertRef;
69+
70+
MismatchType(String ref) {
71+
this.alertRef = String.valueOf(PLUGIN_ID) + ref;
72+
}
73+
74+
String getAlertRef() {
75+
return this.alertRef;
76+
}
6577
}
6678

6779
@Override
@@ -71,9 +83,6 @@ public String getName() {
7183

7284
public String getVariant(MismatchType currentType) {
7385
switch (currentType) {
74-
case NO_MISMATCH_METACONTENTTYPE_MISSING: // no_mismatch_metacontenttype_missing
75-
return Constant.messages.getString(
76-
MESSAGE_PREFIX + "variant.no_mismatch_metacontenttype_missing");
7786
case HEADER_METACONTENTYPE_MISMATCH: // header_metacontentype_mismatch
7887
return Constant.messages.getString(
7988
MESSAGE_PREFIX + "variant.header_metacontentype_mismatch");
@@ -153,55 +162,31 @@ public void scanHttpResponseReceive(HttpMessage msg, int id, Source source) {
153162
// other
154163
if (AlertThreshold.LOW.equals(pluginThreshold)
155164
&& !bodyContentCharset.equalsIgnoreCase(metaCharset)) {
156-
raiseAlert(
157-
msg,
158-
id,
159-
metaCharset,
160-
bodyContentCharset,
161-
MismatchType
162-
.METACONTENTTYPE_METACHARSET_MISMATCH); // body declarations
163-
// inconsistent with
164-
// each other
165+
buildAlert(
166+
metaCharset,
167+
bodyContentCharset,
168+
MismatchType.METACONTENTTYPE_METACHARSET_MISMATCH)
169+
.raise(); // body declarations inconsistent with each other
165170
}
166171
}
167172
if (hasBodyCharset) {
168173
// Check the body content type charset declaration against the header
169174
if (!bodyContentCharset.equalsIgnoreCase(headerCharset)) {
170-
raiseAlert(
171-
msg,
172-
id,
173-
headerCharset,
174-
bodyContentCharset,
175-
MismatchType.HEADER_METACONTENTYPE_MISMATCH); // body declaration
176-
// doesn't match header
175+
buildAlert(
176+
headerCharset,
177+
bodyContentCharset,
178+
MismatchType.HEADER_METACONTENTYPE_MISMATCH)
179+
.raise(); // body declaration doesn't match header
177180
}
178181
}
179182
if (hasMetaCharset) {
180183
// Check the body meta charset declaration against the header
181184
if (!metaCharset.equalsIgnoreCase(headerCharset)) {
182-
raiseAlert(
183-
msg,
184-
id,
185-
headerCharset,
186-
metaCharset,
187-
MismatchType
188-
.HEADER_METACHARSET_MISMATCH); // body declaration doesn't
189-
// match header
190-
}
191-
// If Threshold is LOW be picky and report that
192-
// only a meta charset declaration might be insufficient coverage for older
193-
// clients
194-
if (AlertThreshold.LOW.equals(pluginThreshold) && hasBodyCharset == false) {
195-
raiseAlert(
196-
msg,
197-
id,
198-
"",
199-
"",
200-
MismatchType
201-
.NO_MISMATCH_METACONTENTTYPE_MISSING); // body declaration
202-
// does match header
203-
// but may overlook
204-
// older clients
185+
buildAlert(
186+
headerCharset,
187+
metaCharset,
188+
MismatchType.HEADER_METACHARSET_MISMATCH)
189+
.raise(); // body declaration doesn't match header
205190
}
206191
}
207192
}
@@ -212,11 +197,11 @@ public void scanHttpResponseReceive(HttpMessage msg, int id, Source source) {
212197
// TODO: could there be more than one XML declaration tag for a single XML file?
213198
List<StartTag> xmlDeclarationTags =
214199
source.getAllStartTags(StartTagType.XML_DECLARATION);
215-
if (xmlDeclarationTags.size() > 0) {
200+
if (!xmlDeclarationTags.isEmpty()) {
216201
StartTag xmlDeclarationTag = xmlDeclarationTags.get(0);
217202
String encoding = xmlDeclarationTag.getAttributeValue("encoding");
218203
if (!headerCharset.equalsIgnoreCase(encoding)) {
219-
raiseAlert(msg, id, headerCharset, encoding, MismatchType.XML_MISMATCH);
204+
buildAlert(headerCharset, encoding, MismatchType.XML_MISMATCH).raise();
220205
}
221206
}
222207
}
@@ -259,13 +244,9 @@ private static String getBodyContentCharset(String bodyContentType) {
259244
return charset;
260245
}
261246

262-
private void raiseAlert(
263-
HttpMessage msg,
264-
int id,
265-
String firstCharset,
266-
String secondCharset,
267-
MismatchType currentMismatch) {
268-
newAlert()
247+
private AlertBuilder buildAlert(
248+
String firstCharset, String secondCharset, MismatchType currentMismatch) {
249+
return newAlert()
269250
.setName(
270251
getName()
271252
+ " "
@@ -280,12 +261,12 @@ private void raiseAlert(
280261
.setReference(getReference())
281262
.setCweId(getCweId())
282263
.setWascId(getWascId())
283-
.raise();
264+
.setAlertRef(currentMismatch.getAlertRef());
284265
}
285266

286267
@Override
287268
public int getPluginId() {
288-
return 90011;
269+
return PLUGIN_ID;
289270
}
290271

291272
/*
@@ -327,12 +308,6 @@ private static String getExtraInfo(
327308
String extraInfo = "";
328309

329310
switch (mismatchType) {
330-
case NO_MISMATCH_METACONTENTTYPE_MISSING: // no_mismatch_metacontenttype_missing
331-
extraInfo =
332-
Constant.messages.getString(
333-
MESSAGE_PREFIX
334-
+ "extrainfo.html.no_mismatch_metacontenttype_missing");
335-
break;
336311
case HEADER_METACONTENTYPE_MISMATCH: // header_metacontentype_mismatch
337312
extraInfo =
338313
Constant.messages.getString(
@@ -363,4 +338,26 @@ private static String getExtraInfo(
363338
}
364339
return extraInfo;
365340
}
341+
342+
@Override
343+
public List<Alert> getExampleAlerts() {
344+
return List.of(
345+
buildAlert(
346+
StandardCharsets.UTF_8.name(),
347+
"ISO-123",
348+
MismatchType.HEADER_METACONTENTYPE_MISMATCH)
349+
.build(),
350+
buildAlert(
351+
StandardCharsets.UTF_8.name(),
352+
"ISO-123",
353+
MismatchType.HEADER_METACHARSET_MISMATCH)
354+
.build(),
355+
buildAlert(
356+
"ISO-123",
357+
StandardCharsets.UTF_8.name(),
358+
MismatchType.METACONTENTTYPE_METACHARSET_MISMATCH)
359+
.build(),
360+
buildAlert(StandardCharsets.UTF_8.name(), "ISO-123", MismatchType.XML_MISMATCH)
361+
.build());
362+
}
366363
}

addOns/pscanrules/src/main/javahelp/org/zaproxy/zap/extension/pscanrules/resources/help/contents/pscanrules.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ <H2 id="id-90011">Charset Mismatch</H2>
8989
</li>
9090
<li>Low Threshold:
9191
<ul>
92-
<li>Meta Content-Type Charset Missing - The response doesn't contain a META Content-Type declaration, which may overlook older clients.</li>
9392
<li>Meta Charset Versus Meta Content-Type Charset - The response contains both a META Content-Type declaration and a META Charset declaration, and they don't match.</li>
9493
</ul>
9594
</li>

addOns/pscanrules/src/main/resources/org/zaproxy/zap/extension/pscanrules/resources/Messages.properties

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,13 @@ pscanrules.charsetmismatch.desc = This check identifies responses where the HTTP
4545
pscanrules.charsetmismatch.extrainfo.html.header_metacharset_mismatch = There was a charset mismatch between the HTTP Header and the META charset encoding declaration: [{0}] and [{1}] do not match.
4646
pscanrules.charsetmismatch.extrainfo.html.header_metacontentype_mismatch = There was a charset mismatch between the HTTP Header and the META content-type encoding declarations: [{0}] and [{1}] do not match.
4747
pscanrules.charsetmismatch.extrainfo.html.metacontenttype_metacharset_mismatch = There was a charset mismatch between the META charset and the META content-type encoding declaration: [{0}] and [{1}] do not match.
48-
pscanrules.charsetmismatch.extrainfo.html.no_mismatch_metacontenttype_missing = Charset is defined only by META charset, older clients that expect character set to be defined by META content-type may not correctly display this content.
4948
pscanrules.charsetmismatch.extrainfo.xml = There was a charset mismatch between the HTTP Header and the XML encoding declaration: [{0}] and [{1}] do not match.
5049
pscanrules.charsetmismatch.name = Charset Mismatch
5150
pscanrules.charsetmismatch.refs = https://code.google.com/p/browsersec/wiki/Part2#Character_set_handling_and_detection
5251
pscanrules.charsetmismatch.soln = Force UTF-8 for all text content in both the HTTP header and meta tags in HTML or encoding declarations in XML.
5352
pscanrules.charsetmismatch.variant.header_metacharset_mismatch = (Header Versus Meta Charset)
5453
pscanrules.charsetmismatch.variant.header_metacontentype_mismatch = (Header Versus Meta Content-Type Charset)
5554
pscanrules.charsetmismatch.variant.metacontenttype_metacharset_mismatch = (Meta Charset Versus Meta Content-Type Charset)
56-
pscanrules.charsetmismatch.variant.no_mismatch_metacontenttype_missing = (Meta Content-Type Charset Missing)
5755
5856
pscanrules.contentsecuritypolicymissing.desc = Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement or distribution of malware. CSP provides a set of standard HTTP headers that allow website owners to declare approved sources of content that browsers should be allowed to load on that page — covered types are JavaScript, CSS, HTML frames, fonts, images and embeddable objects such as Java applets, ActiveX, audio and video files.
5957
pscanrules.contentsecuritypolicymissing.name = Content Security Policy (CSP) Header Not Set

0 commit comments

Comments
 (0)