アップデート一覧に戻る
New releaseSep 22, 2026

java-html-sanitizer v20260921.1

サードパーティのHTMLを受け取り、Webアプリケーションに埋め込んでも安全なHTMLを生成します。高速で設定も簡単です。

共有

OWASP Java HTML Sanitizer

Build OpenSSF Best Practices Maven Central

Java で書かれた、高速で設定が容易な HTML サニタイザーです。これにより、 第三者によって作成された HTML を Web アプリケーションに組み込みながら、 XSS から保護することができます。

サニタイザーの JAR にはランタイム依存関係はありません。コンパイル時の 依存関係は spotbugs-annotations(provided スコープ、アノテーションのみ) だけです。その他の JAR はテストスイートでのみ必要です。

このコードはセキュリティのベストプラクティスを念頭に置いて書かれており、 広範なテストスイートを備え、 敵対的セキュリティレビューを受けています。

目次

はじめに

はじめにには、Maven を使用する場合と使用しない場合の 始め方についての手順が記載されています。

リポジトリのレイアウト

ビルドには JDK 11 以降が必要です。リポジトリのルートから、次のコマンドで すべての Maven モジュールをビルドし、そのテストを実行します:

./mvnw clean verify

Maven wrapper は必要な Maven バージョンを固定します。-pl でモジュールを選択する場合は、Maven が依存するモジュールをビルドできるよう -am も併用してください。

  • owasp-java-html-sanitizer/ には、公開されているライブラリ、そのテスト、および Java モジュール記述子が含まれています。
  • java8-shim/ と java10-shim/ は、 ライブラリ JAR にバンドルされる互換性コードを実装しています。
  • examples/ には、参照およびコピー用のサンプルポリシーが含まれています。 テストは行われますが、公開はされません。
  • empiricism/ には、サニタイザーの HTML 要素テーブルを生成するために使用された ブラウザー実験が含まれています。
  • docs/ には、ユーザー向け、セキュリティ、および履歴に関するドキュメントが含まれています。

パッケージ済みポリシー

以下を使用できます: パッケージ済みポリシー:

PolicyFactory policy = Sanitizers.FORMATTING.and(Sanitizers.LINKS);
String safeHTML = policy.sanitize(untrustedHTML);

ポリシーの作成

テストでは、独自のポリシーを設定する方法を示しています:

PolicyFactory policy = new HtmlPolicyBuilder()
    .allowElements("a")
    .allowUrlProtocols("https")
    .allowAttributes("href").onElements("a")
    .requireRelNofollowOnLinks()
    .toFactory();
String safeHTML = policy.sanitize(untrustedHTML);

カスタムポリシー

custom policies を記述することで、h1 を特定のクラスを持つ div に変更するといったことができます:

PolicyFactory policy = new HtmlPolicyBuilder()
    .allowElements("p")
    .allowElements(
        (String elementName, List<String> attrs) -> {
          // Add a class attribute.
          attrs.add("class");
          attrs.add("header-" + elementName);
          // Return elementName to include, null to drop.
          return "div";
        }, "h1", "h2", "h3", "h4", "h5", "h6")
    .toFactory();
String safeHTML = policy.sanitize(untrustedHTML);

要素「a」「font」「img」「input」「span」を、これらの要素に属性が含まれていない場合でもフィルターを通過させたい場合は、allowWithoutAttributes() メソッドを使用して明示的にホワイトリストに登録する必要があることに注意してください。

属性ポリシーでは、カスタムコードを実行することもできます。属性ポリシーを追加しても、style や URL 属性のチェックなどの既定のポリシーが弱まることはありません。

PolicyFactory myPolicy = new HtmlPolicyBuilder()
    .allowElements("div", "span")
    .allowAttributes("data-foo")
        .matching(
            (String elementName, String attributeName, String value) -> {
              // Return value for the attribute or null to drop.
              return value;
            })
        .onElements("div", "span")
    .toFactory();

プリプロセッサ

プリプロセッサを使用すると、テキストの挿入や大規模な構造変更を行うことができます。

PolicyFactory myPolicy = new HtmlPolicyBuilder()
    .withPreprocessor(
        (HtmlStreamEventReceiver r) -> {
          // Provide user with info about links before they click.
          // Before:                       <a href="https://example.com/...">
          // After:  (https://example.com) <a href="https://example.com/...">
          return new HtmlStreamEventReceiverWrapper(r) {
            @Override public void openTag(String elementName, List<String> attrs) {
              if ("a".equals(elementName)) {
                for (int i = 0, n = attrs.size(); i < n; i += 2) {
                  if ("href".equals(attrs.get(i))) {
                    String url = attrs.get(i + 1);
                    String origin;
                    try {
                      URI uri = new URI(url);
                      String scheme = uri.getScheme();
                      String authority = uri.getRawAuthority();
                      if (scheme == null && authority == null) {
                        origin = null;
                      } else {
                        origin = (scheme != null ? scheme + ":" : "")
                               + (authority != null ? "//" + authority : "");
                      }
                    } catch (URISyntaxException ex) {
                      origin = "about:invalid";
                    }
                    if (origin != null) {
                      text(" (" + origin + ") ");
                    }
                  }
                }
              }
              super.openTag(elementName, attrs);
            }
          };
        })
     .allowElements("a")
     .allowAttributes("href").onElements("a")
     .allowStandardUrlProtocols()
    ...
    .toFactory();

前処理はポリシーが適用される前に行われるため、出力のセキュリティに影響を与えることはありません。

テレメトリ

ポリシーが要素または属性を拒否すると、HtmlChangeListener に通知されます。

これを使用して、ポリシー違反の傾向を追跡し、誰かがあなたのセキュリティを侵害しようとしている取り組みを行っているタイミングを把握できます。

PolicyFactory myPolicyFactory = ...;
// If you need to associate reports with some context, you can do so.
MyContextClass myContext = ...;

String sanitizedHtml = myPolicyFactory.sanitize(
    unsanitizedHtml,
    new HtmlChangeListener<MyContextClass>() {
      @Override
      public void discardedTag(MyContextClass context, String elementName) {
        // ...
      }
      @Override
      public void discardedAttributes(
          MyContextClass context, String elementName, String... attributeNames) {
        // ...
      }
    },
    myContext);

discardedAttributes は、属性が拒否された結果として要素自体が破棄された場合にも発火します。たとえば、唯一の href が拒否されたリンクなどが該当します。これをオーバーライドするリスナー向けに、より詳細な情報を提供する 2 つのデフォルトメソッドがあります。discardedAttribute は拒否された各属性の値を受け取り、discardedText はポリシーが保持されたリテラルコンテンツ要素から削除したタグ様のコンテンツ、およびレンダラーがその要素から出力できなかったコンテンツを受け取ります。

注: 文字列が変更通知なしでサニタイズされた場合でも、入力文字列が必ずしも安全に使用できるとは限りません。サニタイザーの出力のみを使用してください。

サニタイザーは、出力が一般的に使用される HTML パーサー間で意味の一致する HTML のサブセットに収まることを保証しますが、通知がないことは入力がそのようなサブセットに収まっていることを意味するのではなく、削除された構造的コンテンツを含んでいないことだけを意味します。

カテゴリ