/* * Copyright 2009-2012 Michael Dalton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jtaint; import java.util.Locale; public final class HtmlValidator { public static final String LINE_SEP = "\r\n"; public static final String DEFAULT_CHARSET = "ISO-8859-1"; public static final String UNKNOWN_CONTENT = "UNKNOWN"; private final String charset; private final String contentType; public HtmlValidator(String charset, String contentType) { if (charset == null) charset = DEFAULT_CHARSET; if (contentType == null) contentType = UNKNOWN_CONTENT; this.charset = charset; this.contentType = contentType; } public String getCharset() { return charset; } public String getContentType() { return contentType; } public void print(String s) { if (!s.@internal@isTainted() || !Configuration.xssPolicyLogVuln) return; @StringBuilder@ sb = new @StringBuilder@(); JTaintException e; sb.append("Cross-site scripting vulnerability detected: outputting "); sb.append("tainted string " + s + " (taint: " + s.@internal@taint()); sb.append(" )\n"); e = new JTaintException(sb.toString(), Configuration.xssWhitelist); Log.vuln("Cross Site Scripting", e); } public void println(String s) { print(s); print(LINE_SEP); } /* XXX TODO - Figure out which of these methods can _never_ result in * XSS and then just skip them entirely, i.e don't even instrument them. * period, and remove the methods from this class. * * Optimize all print(String, type*), print(char[], type*) * and append(CharSequene, type*) methods * * Also if it turns out to more elegant, may want to have an aliasMap and * remove all these crude aliased methods. Furthermore, if \r\n don't * matter (and I seem to recall some obscure case where they do), then * we can treat print/println the same. */ public void print(boolean b) { print(String.valueOf(b)); } public void print(char c) { print(String.valueOf(c)); } public void print(char[] c) { print(new String(c)); } public void print(double d) { print(String.valueOf(d)); } public void print(float f) { print(String.valueOf(f)); } public void print(int i) { print(String.valueOf(i)); } public void print(long l) { print(String.valueOf(l)); } public void print(Object o) { print(String.valueOf(o)); } public void println() { print(LINE_SEP); } public void println(boolean b) { print(String.valueOf(b)); print(LINE_SEP); } public void println(char c) { print(String.valueOf(c)); print(LINE_SEP); } public void println(char[] c) { print(new String(c)); print(LINE_SEP); } public void println(double d) { print(String.valueOf(d)); print(LINE_SEP); } public void println(float f) { print(String.valueOf(f)); print(LINE_SEP); } public void println(int i) { print(String.valueOf(i)); print(LINE_SEP); } public void println(long l) { print(String.valueOf(l)); print(LINE_SEP); } public void println(Object o) { print(String.valueOf(o)); print(LINE_SEP); } //[ifJava5+] public void append(char c) { print(String.valueOf(c)); } public void append(CharSequence cs) { print(cs.toString()); } public void append(CharSequence cs, int start, int end) { print(cs.toString().substring(start, end)); } public void format(String format, Object[] args) { format(Locale.getDefault(), format, args); } public void format(Locale l, String format, Object[] args) { String s = null; try { s = String.format(l, format, args); } catch (Throwable th) { Log.error(th); } if (s != null) print(s); } public void printf(String format, Object[] args) { format(Locale.getDefault(), format, args); } public void printf(Locale l, String format, Object[] args) { format(l, format, args); } //[fiJava5+] public void write(char[] c) { print(new String(c)); } public void write (char[] c, int off, int len) { print(new String(c, off, len)); } /* See java.io.OutputStream:write(int i) */ public void write(byte b) { byte[] ba = new byte[] { b }; write(ba, 0, ba.length); } public void write(byte[] b) { write(b, 0, b.length); } public void write(byte[] b, int off, int len) { String s = null; try { s = new String(b, off, len, charset); } catch (Throwable th) { Log.error(th); } if (s != null) print(s); } public void write(String s) { print(s); } public void write(String s, int off, int len) { print(s.substring(off, off + len)); } }