Tôi đang cố gắng phát triển tiện ích mở rộng/tiện ích bổ sung của Firefox cần truy cập vào thông tin Chứng chỉ SSL của trang hiện được tải . Khi tôi có thông tin này, tôi dự định sửa đổi nội dung của trang dựa trên thông tin SSL. Mặc dù, trước khi tôi đến đó, trước tiên tôi cần có thông tin SSL.Làm cách nào để lấy thông tin Chứng chỉ SSL cho trang * hiện tại * trong Firefox Thêm Vào
Cách tiếp cận được nêu here tạo XMLHTTPRequest riêng biệt để nhận chứng chỉ bảo mật. Tôi không muốn làm điều đó nếu tôi có thể tránh nó vì nó trình bày một vấn đề an ninh.
Ví dụ: trang web độc hại/người ở giữa có thể cung cấp một chứng chỉ về yêu cầu đầu tiên cho trang (trình duyệt sẽ xác minh) và sau đó cung cấp chứng chỉ khác cho XMLHTTPRequest mà tiện ích của tôi sẽ thực hiện. Điều này sẽ dẫn đến việc mở rộng sửa đổi nội dung trang web dựa trên thông tin không phù hợp. Do đó, tôi muốn nhận thông tin SSL Cert mà trình duyệt tự sử dụng khi xác minh trang web.
Với ý nghĩ đó, tôi kết hợp cách tiếp cận trên với phương pháp được nêu trong Altering HTTP Responses in Firefox Extension để chặn tất cả các phản hồi HTTP bằng cách thêm người quan sát sự kiện "http-on-exam-response". Tôi nghĩ rằng với phương pháp này tôi có thể chỉ cần lấy các thông tin cert như nó đã được tải xuống từ trang web.
Đây là thịt của mã của tôi, phần lớn là lấy từ các liên kết trên (phần còn lại là mở rộng của Firefox soạn sẵn):
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);
Những gì tôi thấy là thực hiện này là không phù hợp. Khi tôi tải gmail.com trong Firefox, đôi khi tôi sẽ nhận được thông tin chứng chỉ và đôi khi tôi sẽ không. Tôi nghi ngờ đây là một vấn đề bộ nhớ đệm như làm mới trang thường sẽ dẫn đến thông tin chứng chỉ được tải xuống/in.
Đối với ứng dụng dự định, hành vi này không được chấp nhận. Đây là một dự án nghiên cứu vì vậy, nếu tôi phải, tôi sẽ sẵn sàng sửa đổi mã nguồn Firefox, nhưng ưu tiên của tôi sẽ là làm điều này bằng cách sử dụng API tiện ích mở rộng/tiện ích bổ sung.
Có cách nào tốt hơn, nhất quán hơn để nhận thông tin Chứng chỉ SSL không?
Bạn không nên nuốt lỗi trong 'bạn TracingListener'. Tôi đã từng làm điều này và nhận thấy rằng nó gây ra sự cố do trạng thái không nhất quán. Nếu người nghe ban đầu ném lỗi và bạn không muốn giữ nó (do lỗi trong Bảng điều khiển Lỗi) thì yêu cầu đó sẽ bị hủy. Như thế này: 'catch (e if e instanceof Ci.nsIException) {request.cancel (e.result);}' –
Tôi đã thực hiện một số chỉnh sửa cho câu hỏi theo đề xuất của bạn. Điều đó có xử lý trường hợp bạn mô tả không? –
Có, cách này sẽ hoạt động chính xác. –