Skip to content

Integrate url classifier #126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion docs/maven.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Using with Maven
# Using with Maven

The HTML Sanitizer is available from
[Maven Central](https://search.maven.org/#browse%7C84770979)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.google.common.html.types.SafeHtml;
import com.google.common.html.types.UncheckedConversions;

import org.owasp.html.Context;
import org.owasp.html.HtmlChangeListener;
import org.owasp.html.PolicyFactory;

Expand Down Expand Up @@ -67,27 +68,57 @@ private SafeHtmlMint(PolicyFactory f) {

/** A convenience function that sanitizes a string of HTML. */
public SafeHtml sanitize(@Nullable String html) {
return sanitize(html, null, null);
return sanitize(html, Context.DEFAULT, null, null);
}

/** A convenience function that sanitizes a string of HTML. */
public SafeHtml sanitize(@Nullable String html, @Nullable Context context) {
return sanitize(html, context, null, null);
}

/**
* A convenience function that sanitizes a string of HTML and reports
* the names of rejected element and attributes to listener.
* @param html the string of HTML to sanitize.
* @param context the context of the document that will embed the output.
* @param listener if non-null, receives notifications of tags and attributes
* that were rejected by the policy. This may tie into intrusion
* detection systems.
* @param context if {@code (listener != null)} then the context value passed
* with notifications. This can be used to let the listener know from
* which connection or request the questionable HTML was received.
* @param listenerContext if {@code (listener != null)} then the context
* value passed with notifications. This can be used to let the listener
* know from which connection or request the questionable HTML was
* received.
* @return a string of safe HTML assuming the input policy factory produces
* safe HTML.
*/
public <CTX> SafeHtml sanitize(
@Nullable String html,
@Nullable HtmlChangeListener<CTX> listener, @Nullable CTX context) {
@Nullable HtmlChangeListener<CTX> listener,
@Nullable CTX listenerContext) {
return sanitize(html, Context.DEFAULT, listener, listenerContext);
}

/**
* A convenience function that sanitizes a string of HTML and reports
* the names of rejected element and attributes to listener.
* @param html the string of HTML to sanitize.
* @param context the context of the document that will embed the output.
* @param listener if non-null, receives notifications of tags and attributes
* that were rejected by the policy. This may tie into intrusion
* detection systems.
* @param listenerContext if {@code (listener != null)} then the context
* value passed with notifications. This can be used to let the listener
* know from which connection or request the questionable HTML was
* received.
* @return a string of safe HTML assuming the input policy factory produces
* safe HTML.
*/
public <CTX> SafeHtml sanitize(
@Nullable String html, @Nullable Context context,
@Nullable HtmlChangeListener<CTX> listener,
@Nullable CTX listenerContext) {
if (html == null) { return SafeHtml.EMPTY; }
return UncheckedConversions.safeHtmlFromStringKnownToSatisfyTypeContract(
f.sanitize(html, listener, context));
f.sanitize(html, context, listener, listenerContext));
}
}
11 changes: 11 additions & 0 deletions parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,23 @@ application while protecting against XSS.
<version>[2.0.1,)</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.owasp</groupId>
<artifactId>url</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nu.validator.htmlparser</groupId>
<artifactId>htmlparser</artifactId>
<version>1.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
5 changes: 4 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
<artifactId>annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.owasp</groupId>
<artifactId>url</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand All @@ -75,7 +79,6 @@
<dependency>
<groupId>nu.validator.htmlparser</groupId>
<artifactId>htmlparser</artifactId>
<version>1.4</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
94 changes: 81 additions & 13 deletions src/main/java/org/owasp/html/AttributePolicy.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;

import java.util.Collections;
import java.util.Set;

import javax.annotation.CheckReturnValue;
Expand All @@ -55,43 +56,82 @@
*
* @return {@code null} to disallow the attribute or the adjusted value if
* allowed.
* @deprecated prefer {@link V2#apply(String, String, String, Context)}
*/
@Deprecated
public @Nullable String apply(
String elementName, String attributeName, String value);


/**
* Extends AttributePolicy that receives the embedding document context.
*/
public interface V2 extends AttributePolicy {
/**
* @param elementName the lower-case element name.
* @param attributeName the lower-case attribute name.
* @param value the attribute value without quotes and with HTML entities
* decoded.
* @param context about the document in which the sanitized attribute will
* be embedded.
*
* @return {@code null} to disallow the attribute or the adjusted value if
* allowed.
*/
public @Nullable String apply(
String elementName, String attributeName, String value,
Context context);
}


/** Utilities for working with attribute policies. */
public static final class Util {

static Iterable<AttributePolicy.V2> unjoin(AttributePolicy.V2 p) {
if (p instanceof JoinedAttributePolicy) {
return ((JoinedAttributePolicy) p).policies;
} else {
return Collections.singleton(p);
}
}

/** Adapts an old-style attribute policy to the new interface. */
public static V2 adapt(AttributePolicy p) {
if (p instanceof V2) {
return (V2) p;
}
return new AttributePolicyAdapter(p);
}

/**
* An attribute policy equivalent to applying all the given policies in
* order, failing early if any of them fails.
*/
@CheckReturnValue
public static final AttributePolicy join(AttributePolicy... policies) {
public static final AttributePolicy.V2 join(AttributePolicy... policies) {
AttributePolicyJoiner joiner = new AttributePolicyJoiner();

for (AttributePolicy p : policies) {
if (p != null) {
joiner.unroll(p);
joiner.unroll(adapt(p));
}
}

return joiner.join();
}

static final class AttributePolicyJoiner
extends JoinHelper<AttributePolicy, JoinableAttributePolicy> {
extends JoinHelper<AttributePolicy.V2, JoinableAttributePolicy> {

AttributePolicyJoiner() {
super(AttributePolicy.class,
super(AttributePolicy.V2.class,
JoinableAttributePolicy.class,
REJECT_ALL_ATTRIBUTE_POLICY,
IDENTITY_ATTRIBUTE_POLICY);
}

@Override
Optional<ImmutableList<AttributePolicy>> split(AttributePolicy x) {
Optional<ImmutableList<AttributePolicy.V2>> split(AttributePolicy.V2 x) {
if (x instanceof JoinedAttributePolicy) {
return Optional.of(((JoinedAttributePolicy) x).policies);
} else {
Expand All @@ -100,34 +140,62 @@ Optional<ImmutableList<AttributePolicy>> split(AttributePolicy x) {
}

@Override
AttributePolicy rejoin(Set<? extends AttributePolicy> xs) {
AttributePolicy.V2 rejoin(Set<? extends AttributePolicy.V2> xs) {
return new JoinedAttributePolicy(xs);
}

}

/** The old apply method forwards a null context to the V2 apply method. */
public static abstract class AbstractV2AttributePolicy implements V2 {
public final @Nullable String apply(
String elementName, String attributeName, String value) {
return apply(elementName, attributeName, value, null);
}
}

static final class AttributePolicyAdapter
extends AbstractV2AttributePolicy {

final AttributePolicy p;

AttributePolicyAdapter(AttributePolicy p) {
this.p = p;
}

public String apply(
String elementName, String attributeName, String value,
Context context) {
return p.apply(elementName, attributeName, value);
}

}
}


/** An attribute policy that returns the value unchanged. */
public static final AttributePolicy IDENTITY_ATTRIBUTE_POLICY
= new AttributePolicy() {
public static final AttributePolicy.V2 IDENTITY_ATTRIBUTE_POLICY
= new Util.AbstractV2AttributePolicy() {
public String apply(
String elementName, String attributeName, String value) {
String elementName, String attributeName, String value,
Context context) {
return value;
}
};

/** An attribute policy that rejects all values. */
public static final AttributePolicy REJECT_ALL_ATTRIBUTE_POLICY
= new AttributePolicy() {
public static final AttributePolicy.V2 REJECT_ALL_ATTRIBUTE_POLICY
= new Util.AbstractV2AttributePolicy() {
public @Nullable String apply(
String elementName, String attributeName, String value) {
String elementName, String attributeName, String value,
Context context) {
return null;
}
};

/** An attribute policy that is joinable. */
static interface JoinableAttributePolicy
extends AttributePolicy, Joinable<JoinableAttributePolicy> {
extends AttributePolicy.V2, Joinable<JoinableAttributePolicy> {
// Parameterized Appropriately.
}
}
55 changes: 55 additions & 0 deletions src/main/java/org/owasp/html/Context.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) 2017, Mike Samuel
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// Neither the name of the OWASP nor the names of its contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

package org.owasp.html;

import org.owasp.url.UrlContext;

/**
* The context in which the sanitized output will be used.
*/
public final class Context {
private final UrlContext urlContext;

/** A least common denominator context. */
public static final Context DEFAULT = new Context(UrlContext.DEFAULT);

/**
* @param urlContext The URL context for the embedding document.
*/
public Context(UrlContext urlContext) {
this.urlContext = urlContext;
}

/**
* The URL context for the embedding document.
*/
public UrlContext urlContext() {
return urlContext;
}
}
Loading