gpt4 book ai didi

javascript - 如何获取 Firefox 附加组件中*当前*页面的 SSL 证书信息

转载 作者:数据小太阳 更新时间:2023-10-29 06:13:19 34 4
gpt4 key购买 nike

我正在尝试开发需要访问当前加载页面的 SSL 证书信息的 Firefox 扩展/附加组件。获得此信息后,我计划根据 SSL 信息修改页面内容。不过,在我到达那里之前,我首先需要获取 SSL 信息。

概述的方法 here发出单独的 XMLHTTPRequest 以获取安全证书。如果可以避免,我宁愿不这样做,因为它会带来安全问题。

例如,恶意网站/中间人可以在第一次请求页面时提供一个证书(浏览器会验证),然后为我的扩展程序将发出的 XMLHTTPRequest 提供另一个证书。这将导致扩展根据不一致的信息修改站点内容。因此,我想获取浏览器本身在验证站点时使用的 SSL 证书信息。

考虑到这一点,我将上述方法与 Altering HTTP Responses in Firefox Extension 中概述的方法相结合通过添加“http-on-examine-response”事件的观察者来拦截所有 HTTP 响应。我认为使用这种方法我可以简单地获取从站点下载的证书信息。

这是我的代码的主要部分,其中大部分来自上述链接(其余部分是 Firefox 扩展样板):

function dumpSecurityInfo(channel) {

const Cc = Components.classes
const Ci = Components.interfaces;

// Do we have a valid channel argument?
if (! channel instanceof Ci.nsIChannel) {
dump("No channel available\n");
return;
}

var secInfo = channel.securityInfo;


// Print general connection security state

if (secInfo instanceof Ci.nsITransportSecurityInfo) {
dump("name: " + channel.name + "\n");
secInfo.QueryInterface(Ci.nsITransportSecurityInfo);

dump("\tSecurity state: ");

// Check security state flags
if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_SECURE) == Ci.nsIWebProgressListener.STATE_IS_SECURE)
dump("secure\n");

else if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_INSECURE) == Ci.nsIWebProgressListener.STATE_IS_INSECURE)
dump("insecure\n");

else if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_BROKEN) == Ci.nsIWebProgressListener.STATE_IS_BROKEN)
dump("unknown\n");

dump("\tSecurity description: " + secInfo.shortSecurityDescription + "\n");
dump("\tSecurity error message: " + secInfo.errorMessage + "\n");
}

// Print SSL certificate details
if (secInfo instanceof Ci.nsISSLStatusProvider) {

var cert = secInfo.QueryInterface(Ci.nsISSLStatusProvider).
SSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert;

dump("\nCertificate Status:\n");

var verificationResult = cert.verifyForUsage(Ci.nsIX509Cert.CERT_USAGE_SSLServer);
dump("\tVerification: ");

switch (verificationResult) {
case Ci.nsIX509Cert.VERIFIED_OK:
dump("OK");
break;
case Ci.nsIX509Cert.NOT_VERIFIED_UNKNOWN:
dump("not verfied/unknown");
break;
case Ci.nsIX509Cert.CERT_REVOKED:
dump("revoked");
break;
case Ci.nsIX509Cert.CERT_EXPIRED:
dump("expired");
break;
case Ci.nsIX509Cert.CERT_NOT_TRUSTED:
dump("not trusted");
break;
case Ci.nsIX509Cert.ISSUER_NOT_TRUSTED:
dump("issuer not trusted");
break;
case Ci.nsIX509Cert.ISSUER_UNKNOWN:
dump("issuer unknown");
break;
case Ci.nsIX509Cert.INVALID_CA:
dump("invalid CA");
break;
default:
dump("unexpected failure");
break;
}
dump("\n");

dump("\tCommon name (CN) = " + cert.commonName + "\n");
dump("\tOrganisation = " + cert.organization + "\n");
dump("\tIssuer = " + cert.issuerOrganization + "\n");
dump("\tSHA1 fingerprint = " + cert.sha1Fingerprint + "\n");

var validity = cert.validity.QueryInterface(Ci.nsIX509CertValidity);
dump("\tValid from " + validity.notBeforeGMT + "\n");
dump("\tValid until " + validity.notAfterGMT + "\n");
}
}

function TracingListener() {
}

TracingListener.prototype =
{
originalListener: null,

onDataAvailable: function(request, context, inputStream, offset, count) {
try
{
dumpSecurityInfo(request)
this.originalListener.onDataAvailable(request, context, inputStream, offset, count);
} catch (err) {
dump(err);
if (err instanceof Ci.nsIException)
{
request.cancel(e.result);
}
}
},

onStartRequest: function(request, context) {
try
{
dumpSecurityInfo(request)
this.originalListener.onStartRequest(request, context);
} catch (err) {
dump(err);
if (err instanceof Ci.nsIException)
{
request.cancel(e.result);
}
}
},

onStopRequest: function(request, context, statusCode) {
this.originalListener.onStopRequest(request, context, statusCode);
},

QueryInterface: function (aIID) {
const Ci = Components.interfaces;
if ( iid.equals(Ci.nsIObserver) ||
iid.equals(Ci.nsISupportsWeakReference) ||
iid.equals(Ci.nsISupports))
{
return this;
}
throw Components.results.NS_NOINTERFACE;
}
}


var httpRequestObserver =
{
observe: function(aSubject, aTopic, aData)
{
const Ci = Components.interfaces;
if (aTopic == "http-on-examine-response")
{
var newListener = new TracingListener();
aSubject.QueryInterface(Ci.nsITraceableChannel);
newListener.originalListener = aSubject.setNewListener(newListener);
}
},

QueryInterface : function (aIID)
{
const Ci = Components.interfaces;
if (aIID.equals(Ci.nsIObserver) ||
aIID.equals(Ci.nsISupports))
{
return this;
}

throw Components.results.NS_NOINTERFACE;

}
};

var test =
{
run: function() {
const Ci = Components.interfaces;
dump("run");
var observerService = Components.classes["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
observerService.addObserver(httpRequestObserver,
"http-on-examine-response", false);
}
};

window.addEventListener("load", function () { test.run(); }, false);

我发现这个实现是不一致的。当我在 Firefox 中加载 gmail.com 时,我有时会获得证书信息,有时则不会。我怀疑这是一个缓存问题,因为刷新页面通常会导致下载/打印证书信息。

对于我的预期应用程序,这种行为是 Not Acceptable 。这是一个研究项目,因此,如果必须的话,我愿意修改 Firefox 源代码,但我更喜欢使用扩展/附加 API 来完成此操作。

是否有更好、更一致的方式来获取 SSL 证书信息?

最佳答案

基于 this回答:

诀窍是注册一个 progress listener并在调用 onSecurityChange 函数时检查 aState。如果设置了 Ci.nsIWebProgressListener.STATE_IS_SECURE 标志,则页面正在使用 SSL 连接。然而,这还不够,aRequest 参数可能不是 Ci.nsIChannel 的实例,应该首先使用 if (aRequest instanceof Ci.nsIChannel )

这是工作代码:

function dumpSecurityInfo(channel) {

const Cc = Components.classes
const Ci = Components.interfaces;

// Do we have a valid channel argument?
if (! channel instanceof Ci.nsIChannel) {
dump("No channel available\n");
return;
}

var secInfo = channel.securityInfo;

// Print general connection security state
if (secInfo instanceof Ci.nsITransportSecurityInfo) {
dump("name: " + channel.name + "\n");
secInfo.QueryInterface(Ci.nsITransportSecurityInfo);

dump("\tSecurity state: ");

// Check security state flags
if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_SECURE) == Ci.nsIWebProgressListener.STATE_IS_SECURE)
dump("secure\n");

else if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_INSECURE) == Ci.nsIWebProgressListener.STATE_IS_INSECURE)
dump("insecure\n");

else if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_BROKEN) == Ci.nsIWebProgressListener.STATE_IS_BROKEN)
dump("unknown\n");

dump("\tSecurity description: " + secInfo.shortSecurityDescription + "\n");
dump("\tSecurity error message: " + secInfo.errorMessage + "\n");
}
else {

dump("\tNo security info available for this channel\n");
}

// Print SSL certificate details
if (secInfo instanceof Ci.nsISSLStatusProvider) {

var cert = secInfo.QueryInterface(Ci.nsISSLStatusProvider).
SSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert;

dump("\nCertificate Status:\n");

var verificationResult = cert.verifyForUsage(Ci.nsIX509Cert.CERT_USAGE_SSLServer);
dump("\tVerification: ");

switch (verificationResult) {
case Ci.nsIX509Cert.VERIFIED_OK:
dump("OK");
break;
case Ci.nsIX509Cert.NOT_VERIFIED_UNKNOWN:
dump("not verfied/unknown");
break;
case Ci.nsIX509Cert.CERT_REVOKED:
dump("revoked");
break;
case Ci.nsIX509Cert.CERT_EXPIRED:
dump("expired");
break;
case Ci.nsIX509Cert.CERT_NOT_TRUSTED:
dump("not trusted");
break;
case Ci.nsIX509Cert.ISSUER_NOT_TRUSTED:
dump("issuer not trusted");
break;
case Ci.nsIX509Cert.ISSUER_UNKNOWN:
dump("issuer unknown");
break;
case Ci.nsIX509Cert.INVALID_CA:
dump("invalid CA");
break;
default:
dump("unexpected failure");
break;
}
dump("\n");

dump("\tCommon name (CN) = " + cert.commonName + "\n");
dump("\tOrganisation = " + cert.organization + "\n");
dump("\tIssuer = " + cert.issuerOrganization + "\n");
dump("\tSHA1 fingerprint = " + cert.sha1Fingerprint + "\n");

var validity = cert.validity.QueryInterface(Ci.nsIX509CertValidity);
dump("\tValid from " + validity.notBeforeGMT + "\n");
dump("\tValid until " + validity.notAfterGMT + "\n");
}
}

var myListener =
{
QueryInterface: function(aIID)
{
if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
aIID.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_NOINTERFACE;
},

onStateChange: function(aWebProgress, aRequest, aFlag, aStatus) { },

onLocationChange: function(aProgress, aRequest, aURI) { },

onProgressChange: function(aWebProgress, aRequest, curSelf, maxSelf, curTot, maxTot) { },
onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) { },
onSecurityChange: function(aWebProgress, aRequest, aState)
{
// check if the state is secure or not
if(aState & Ci.nsIWebProgressListener.STATE_IS_SECURE)
{
// this is a secure page, check if aRequest is a channel,
// since only channels have security information
if (aRequest instanceof Ci.nsIChannel)
{
dumpSecurityInfo(aRequest);
}
}
}
}

var test =
{
run: function() {
dump("run\n");
gBrowser.addProgressListener(myListener);
}
};

window.addEventListener("load", function () { test.run(); }, false);

关于javascript - 如何获取 Firefox 附加组件中*当前*页面的 SSL 证书信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6983401/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com