我正在尝试在我们的应用程序的tomcat服务器中启用HPKP证书固定。我添加了一个过滤器以包含HSTS和HPKP指令。我按预期在响应标头中获得了HSTS和HPKP指令。

但是,即使我在服务器中更改了证书或拦截了请求并发送了伪造的证书,浏览器也不会停止请求。浏览器具有HPKP功能,因为当请求被拦截并显示伪造证书时,它会阻止其他启用HPKP的网站,例如facebook。

只是想知道我生成公钥哈希值的方式是否有误,因此浏览器没有固定密钥?如果有人为雄猫启用了HPKP,是否有任何反馈?

在web.xml中添加了过滤器

    <filter>
            <filter-name>HttpsSecFilter</filter-name>
            <filter-class>com.x.x.x.x.x.HttpsSecurityFilter</filter-class>
    </filter>
    <filter-mapping>
            <filter-name>HttpsSecFilter</filter-name>
            <url-pattern>..[url-pattern]..</url-pattern>
    </filter-mapping>


过滤器代码(为简洁起见,已修改为仅包括相关部分)

public class HttpsSecurityFilter implements Filter {
    private boolean _isHTTSEnabled = false;
    private long _httsMaxAge = -1;

    private boolean _isHPKPEnabled = false;
    private long _hpkpMaxAge = -1;
    private String _hpkpCertHashesString = null;

    private boolean _includeSubdomains = false;

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {

        if (_isHTTSEnabled && response instanceof HttpServletResponse) {
            ((HttpServletResponse) response).setHeader("Strict-Transport-Security",
                                                       "max-age=" + _httsMaxAge);
        }

        if (_isHPKPEnabled && response instanceof HttpServletResponse) {
            ((HttpServletResponse) response).setHeader("Public-Key-Pins",
                                                       _hpkpCertHashesString);
        }

        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        //Read from application configuration file
        _isHTTSEnabled = true;
        _httsMaxAge = 5184000;

        _isHPKPEnabled = true;
        _hpkpMaxAge = 5184000;
        _includeSubdomains = false;

        if (_isHTTSEnabled) {

            try {
                KeyStore keyStore = KeyStore.getInstance("JKS");
                InputStream is = new FileInputStream(APP_HOME + "/conf/keystore");
                keyStore.load(is, keysotrePassword);
                is.close();

                Certificate cert = keyStore.getCertificate(myappcetificatealias);

                MessageDigest md = MessageDigest.getInstance("SHA-256");
                byte[] digest = md.digest(cert.getPublicKey().getEncoded());
                _hpkpCertHashesString = "pin-sha256=\"" + java.util.Base64.getEncoder()
                                        .encodeToString(digest) + "\"; max-age=" +
                                         _hpkpMaxAge;
            } catch (Exception e) {
                ;
            }
        }
    }
}


来自响应标头的指令

Public-Key-Pins:pin-sha256="JdZ3itf02UwsCav0X26wcSQLGfo="; max-age=5184000
Strict-Transport-Security:max-age=5184000

最佳答案

HTTP的公共密钥固定扩展(HPKP)是一项安全功能,它告诉Web客户端将特定的加密公共密钥与某个Web服务器相关联,以降低使用伪造证书进行MITM攻击的风险。

不幸的是,Apache Tomcat不支持HPKP过滤器。因此,我们必须编写自己的“全局过滤器” Valve。
首先,您需要从证书或密钥文件中提取公钥信息,并使用Base64对其进行编码。
以下命令将帮助您从密钥文件,证书签名请求或证书中提取Base64编码的信息。

openssl rsa -in my-rsa-key-file.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64

openssl ec -in my-ecc-key-file.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64

openssl req -in my-signing-request.csr -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

openssl x509 -in my-certificate.crt -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64


以下命令将提取网站的Base64编码信息。

openssl s_client -servername www.example.com -connect www.example.com:443 | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64


HPKP标头示例

Public-Key-Pins:
  pin-sha256="cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=";
  pin-sha256="M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=";
  max-age=5184000; includeSubDomains;
  report-uri="https://www.example.org/hpkp-report"


在此示例中,pin-sha256 =“ cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2 + soZS7sWs =”锁定生产中使用的服务器公钥。第二个引脚声明pin-sha256 =“ M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE =”也会锁定备份密钥。 max-age = 5184000告诉客户端将这些信息存储两个月,根据IETF RFC,这是一个合理的期限。此键固定对所有子域均有效,这由includeSubDomains声明告知。最后,report-uri =“ https://www.example.net/hpkp-report”解释了报告引脚验证失败的位置。
现在,如下所述创建一个Valve。
创建一个Maven Java应用程序。
添加以下依赖项:

<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>catalina</artifactId>
<version>6.0.53</version>
<scope>provided</scope>
</dependency>



创建Java类,并从ValveBase对其进行扩展。
实现invoke(Request,Response)方法。

public class GlobalFilterValve extends ValveBase {

    @Override
    public void invoke(Request request, Response response) throws IOException, ServletException {
    response.setHeader("Public-Key-Pins", "pin-sha256=\"cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=\"; pin-sha256=\"M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=\"; max-age=5184000; includeSubDomains");
    getNext().invoke(request, response);
    }

}

构建您的库(.jar)文件
将jar文件复制到$ {tomcat.home} / lib目录中。
配置server.xml以使用新的阀门。例如:



<valve className="org.devan.GlobalFilterValve"/>




启动服务器以查看新阀门的运行情况


谢谢 !

关于java - Tomcat过滤器,用于启用HPKP,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39425175/

10-09 05:21