JEditorPaneHTMLEditorKitParserMethodFilter过滤

wen java案例 1

本文目录导读:

JEditorPaneHTMLEditorKitParserMethodFilter过滤

  1. 基本使用示例
  2. 自定义 ParserMethodFilter
  3. 完整的高级示例
  4. 使用 ParserMethodFilter 的安全过滤
  5. 使用建议

我来为您详细解释 JEditorPane、HTMLEditorKit 和 ParserMethodFilter 在 Java Swing 中的使用。

这三个组件通常一起使用来实现 HTML 内容的解析和过滤功能:

  • JEditorPane:Swing 中的 HTML 显示组件
  • HTMLEditorKit:负责 HTML 的编辑和显示
  • ParserMethodFilter:用于过滤 HTML 解析过程中的特定元素

基本使用示例

import javax.swing.*;
import javax.swing.text.html.*;
import javax.swing.text.html.parser.*;
public class HTMLFilterExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame("HTML Filter Example");
        JEditorPane editorPane = new JEditorPane();
        // 创建并配置 HTMLEditorKit
        HTMLEditorKit kit = new HTMLEditorKit();
        // 设置自定义的 ParserMethodFilter
        HTMLParser parser = new HTMLParser() {
            @Override
            protected HTMLParserCallback createParserCallback() {
                return new HTMLParserCallback() {
                    @Override
                    public void handleStartTag(TagElement tag, MutableAttributeSet attrs) {
                        if (!shouldFilter(tag)) {
                            super.handleStartTag(tag, attrs);
                        }
                    }
                    @Override
                    public void handleEndTag(TagElement tag) {
                        if (!shouldFilter(tag)) {
                            super.handleEndTag(tag);
                        }
                    }
                    private boolean shouldFilter(TagElement tag) {
                        String tagName = tag.getHTMLTag().toString();
                        // 过滤特定的标签
                        return tagName.equals("script") || 
                               tagName.equals("iframe");
                    }
                };
            }
        };
        // 应用设置
        kit.setParser(parser);
        editorPane.setEditorKit(kit);
        // 加载 HTML 内容
        String html = "<html><body>" +
                      "<h1>Hello World</h1>" +
                      "<script>alert('XSS');</script>" +
                      "<p>Safe content</p>" +
                      "</body></html>";
        editorPane.setText(html);
        editorPane.setEditable(false);
        frame.add(new JScrollPane(editorPane));
        frame.setSize(500, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

自定义 ParserMethodFilter

public class CustomParserMethodFilter {
    // 使用 ParserMethodFilter 过滤特定 HTML 元素
    public static void applyFilter(JEditorPane editorPane) {
        HTMLEditorKit kit = (HTMLEditorKit) editorPane.getEditorKit();
        // 创建过滤器
        ParserMethodFilter filter = new ParserMethodFilter() {
            @Override
            public boolean acceptMethod(String methodName) {
                // 只允许特定的解析方法
                return methodName.equals("handleStartTag") || 
                       methodName.equals("handleEndTag") || 
                       methodName.equals("handleSimpleTag") ||
                       methodName.equals("handleText");
            }
            @Override
            public boolean acceptParameter(String methodName, 
                                         Object[] parameters) {
                // 对特定参数进行过滤
                if (methodName.equals("handleStartTag")) {
                    if (parameters.length > 0 && 
                        parameters[0] instanceof HTML.Tag) {
                        HTML.Tag tag = (HTML.Tag) parameters[0];
                        // 阻止 script 标签的解析
                        return !tag.equals(HTML.Tag.SCRIPT);
                    }
                }
                return true;
            }
        };
        // 应用过滤器
        // 注意:这里需要扩展 HTMLEditorKit 或使用反射机制
    }
}

完整的高级示例

import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import javax.swing.text.html.parser.*;
import java.awt.*;
import java.io.*;
import java.net.*;
public class AdvancedHTMLFilterDemo extends JFrame {
    private JEditorPane editorPane;
    private JTextArea logArea;
    public AdvancedHTMLFilterDemo() {
        setTitle("HTML Filter Demo");
        setLayout(new BorderLayout());
        // 创建编辑器面板
        editorPane = new JEditorPane();
        editorPane.setContentType("text/html");
        // 自定义 HTMLEditorKit
        CustomHTMLKit kit = new CustomHTMLKit();
        editorPane.setEditorKit(kit);
        editorPane.setEditable(false);
        // 日志面板
        logArea = new JTextArea(5, 40);
        logArea.setEditable(false);
        // 控制按钮
        JButton loadButton = new JButton("Load HTML");
        loadButton.addActionListener(e -> loadSampleHTML());
        // 布局
        add(new JScrollPane(editorPane), BorderLayout.CENTER);
        add(new JScrollPane(logArea), BorderLayout.SOUTH);
        add(loadButton, BorderLayout.NORTH);
        setSize(600, 500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    private void loadSampleHTML() {
        String html = "<html>\n" +
                      "<head><title>Test</title></head>\n" +
                      "<body>\n" +
                      "  <h1>Safe Content</h1>\n" +
                      "  <p>This is safe paragraph</p>\n" +
                      "  <script>alert('Blocked!');</script>\n" +
                      "  <a href='https://example.com'>Link</a>\n" +
                      "  <iframe src='https://evil.com'></iframe>\n" +
                      "</body>\n" +
                      "</html>";
        editorPane.setText(html);
    }
    // 自定义 HTMLEditorKit
    class CustomHTMLKit extends HTMLEditorKit {
        @Override
        public Document createDefaultDocument() {
            HTMLDocument doc = new HTMLDocument() {
                @Override
                public HTMLEditorKit.ParserCallback getReader(int pos) {
                    return new FilteredHTMLReader(pos);
                }
            };
            return doc;
        }
        private class FilteredHTMLReader extends HTMLDocument.HTMLReader {
            public FilteredHTMLReader(int offset) {
                super(offset);
            }
            @Override
            public void handleStartTag(TagElement t, 
                                     MutableAttributeSet a, 
                                     int pos) {
                String tagName = t.getHTMLTag().toString();
                // 过滤不安全标签
                if (tagName.equals("script") || tagName.equals("iframe")) {
                    logArea.append("Filtered out: <" + tagName + ">\n");
                    return;  // 跳过该标签
                }
                // 过滤特定属性
                if (tagName.equals("a") || tagName.equals("img")) {
                    String src = (String) a.getAttribute(HTML.Attribute.SRC);
                    String href = (String) a.getAttribute(HTML.Attribute.HREF);
                    if (src != null && src.startsWith("javascript:")) {
                        logArea.append("Blocked javascript in src\n");
                        return;
                    }
                    if (href != null && href.startsWith("javascript:")) {
                        logArea.append("Blocked javascript in href\n");
                        return;
                    }
                }
                super.handleStartTag(t, a, pos);
            }
            @Override
            public void handleSimpleTag(TagElement t, 
                                      MutableAttributeSet a, 
                                      int pos) {
                String tagName = t.getHTMLTag().toString();
                if (tagName.equals("img")) {
                    String src = (String) a.getAttribute(HTML.Attribute.SRC);
                    if (src != null && !isValidImageSource(src)) {
                        logArea.append("Blocked image: " + src + "\n");
                        return;
                    }
                }
                super.handleSimpleTag(t, a, pos);
            }
            private boolean isValidImageSource(String src) {
                return !src.startsWith("data:") || 
                       src.startsWith("data:image/");
            }
        }
    }
    // 更高级的过滤器 - 使用 ParserMethodFilter
    class SecurityFilter implements ParserMethodFilter {
        @Override
        public boolean acceptMethod(String methodName) {
            // 允许的解析方法
            String[] allowedMethods = {
                "handleStartTag", "handleEndTag", "handleSimpleTag",
                "handleText", "handleComment", "handleError"
            };
            for (String method : allowedMethods) {
                if (method.equals(methodName)) {
                    return true;
                }
            }
            return false;
        }
        @Override
        public boolean acceptParameter(String methodName, 
                                     Object[] parameters) {
            // 对特定方法进行参数验证
            if (methodName.equals("handleStartTag")) {
                if (parameters.length >= 1 && 
                    parameters[0] instanceof TagElement) {
                    TagElement tag = (TagElement) parameters[0];
                    String tagName = tag.getHTMLTag().toString();
                    // 黑名单标签
                    String[] blacklist = {
                        "script", "iframe", "object", "embed", "applet"
                    };
                    for (String blocked : blacklist) {
                        if (tagName.equals(blocked)) {
                            logArea.append("Blocked tag: " + tagName + "\n");
                            return false;
                        }
                    }
                }
            }
            // 检查属性中的潜在危险内容
            if (methodName.equals("handleStartTag") || 
                methodName.equals("handleSimpleTag")) {
                if (parameters.length >= 2 && 
                    parameters[1] instanceof MutableAttributeSet) {
                    MutableAttributeSet attrs = 
                        (MutableAttributeSet) parameters[1];
                    // 检查事件处理器
                    Enumeration<?> attrNames = attrs.getAttributeNames();
                    while (attrNames.hasMoreElements()) {
                        Object attrName = attrNames.nextElement();
                        if (attrName instanceof HTML.Attribute) {
                            HTML.Attribute attr = (HTML.Attribute) attrName;
                            if (attr.toString().startsWith("on")) {
                                logArea.append("Blocked event handler: " + 
                                              attr + "\n");
                                return false;
                            }
                        }
                    }
                }
            }
            return true;
        }
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new AdvancedHTMLFilterDemo().setVisible(true);
        });
    }
}

使用 ParserMethodFilter 的安全过滤

import javax.swing.text.html.parser.*;
public class SecureHTMLParser extends DocumentParser {
    private ParserMethodFilter filter;
    public SecureHTMLParser() {
        this.filter = new DefaultFilter();
    }
    public SecureHTMLParser(ParserMethodFilter filter) {
        this.filter = filter;
    }
    @Override
    protected void handleStartTag(TagElement tag) {
        if (filter.acceptMethod("handleStartTag")) {
            Object[] params = {tag, getAttributes()};
            if (filter.acceptParameter("handleStartTag", params)) {
                super.handleStartTag(tag);
            } else {
                logWarning("Start tag filtered: " + tag.getHTMLTag());
            }
        }
    }
    @Override
    protected void handleEndTag(TagElement tag) {
        if (filter.acceptMethod("handleEndTag")) {
            super.handleEndTag(tag);
        }
    }
    private void logWarning(String message) {
        System.err.println("[Security] " + message);
    }
    // 默认过滤器实现
    static class DefaultFilter implements ParserMethodFilter {
        @Override
        public boolean acceptMethod(String methodName) {
            return true;  // 默认接受所有方法
        }
        @Override
        public boolean acceptParameter(String methodName, 
                                     Object[] parameters) {
            return true;  // 默认接受所有参数
        }
    }
}

使用建议

  1. 性能考虑:过滤操作会增加解析时间,建议在需要时启用
  2. 安全级别:根据应用需求选择合适的过滤策略
  3. 兼容性:确保过滤后的 HTML 仍然保持正确的结构和显示
  4. 错误处理:做好过滤异常的处理和日志记录

这个示例展示了如何使用 JEditorPane、HTMLEditorKit 和 ParserMethodFilter 来实现 HTML 内容的安全过滤和自定义解析。

抱歉,评论功能暂时关闭!