現在ロードされているページのSSL証明書情報へのアクセスが必要なFirefox拡張機能/アドオンを開発しようとしています。この情報を取得したら、SSL情報に基づいてページの内容を変更する予定です。しかし、私がそこに着く前にまずSSL情報を入手する必要があります。Firefoxの*現在のページのSSL証明書情報を入手するにはどうすればいいですか?アドオン
アプローチは、セキュリティ証明書を取得するために別のXMLHTTPRequestをしますhereを概説しました。私はそれがセキュリティの問題を提示するので、私はそれを避けることができたら、私はむしろそれをしないだろう。
例えば、悪意のあるサイト/中間者は、ブラウザが確認するページの最初のリクエストで1つの証明書を提供し、次に自分の拡張が行うXMLHTTPRequestの別の証明書を提供する可能性があります。これにより、矛盾した情報に基づいてサイトの内容を変更する拡張が行われます。したがって、サイトを確認するときにブラウザ自体が使用したSSL証明書情報を取得したいと考えています。
これを念頭に置いて、私はAltering HTTP Responses in Firefox Extensionで概説された方法と上記の方法を組み合わせて、「http-on-examine-response」イベントのオブザーバーを追加することによってすべてのHTTP応答をインターセプトします。私は、この方法では、サイトからダウンロードされたときに証明書情報を取得することができたと考えました。どのような私が見つけたことは、この実装に一貫性がないということである
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の拡張機能の定型である)から取られた、私のコードの肉です。 Firefoxでgmail.comを読み込むと、時には証明書の情報が得られることもあります。ページを更新すると、通常、証明書情報がダウンロード/印刷されるため、これはキャッシングの問題と思われます。
私の意図するアプリケーションでは、この動作は受け入れられません。これは研究プロジェクトのためのものです。もし必要ならば、私はFirefoxのソースコードを変更したいと思っていますが、私の好みは拡張機能/アドオンAPIを使ってこれを行うことです。
SSL証明書情報を取得するためのより良い、より一貫した方法がありますか?
あなたの 'TracingListener'のエラーを飲み込むべきではありません。私はこれをして、それが矛盾した状態のためにクラッシュを引き起こすことに気づいた。元のリスナーがエラーをスローし、それを保持したくない場合(エラーコンソールのスパムのため)、リクエストをキャンセルする必要があります。このように: 'catch(e if instance if Ci.nsIException){request.cancel(e.result);}' –
あなたの提案に応じて質問を編集しました。それは、あなたが描いた事件を処理しますか? –
はい、このように正しく動作するはずです。 –