2017-12-05 38 views
5

Tôi đang làm việc trên một ứng dụng web cần triển khai SSL SAML bằng cách sử dụng idP của bên thứ ba (khởi động SP). Tôi đã đạt đến điểm mà tôi nhận được SAMLResponse từ IDP mà trông như thế này:Xác thực Chữ ký Phản hồi SAML lõi Asp.Net

<?xml version="1.0" encoding="UTF-8"?> 
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" InResponseTo="63622fa6-9a00-4d39-9c92-791c3a1efc3f" IssueInstant="2017-12-04T13:47:30Z" ID="mjmobamignjdlgkpmkiijfbknamlbkadhkjcamhp" Version="2.0"> 
    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://idp.com</saml:Issuer> 
    <samlp:Status> 
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> 
    </samlp:Status> 
    <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="gkifgihgclegelojncjfgegcddfncgdaefcjgbod" IssueInstant="2017-12-04T13:47:30Z" Version="2.0"> 
    <saml:Issuer>https://idp.com</saml:Issuer> 
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 
     <ds:SignedInfo> 
     <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> 
     <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> 
     <ds:Reference URI="#gkifgihgclegelojncjfgegcddfncgdaefcjgbod"> 
      <ds:Transforms> 
      <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> 
      <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> 
      </ds:Transforms> 
      <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
      <ds:DigestValue>nyU3iydIomlY9+D+YO7E6zNyq1A=</ds:DigestValue> 
     </ds:Reference> 
     </ds:SignedInfo> 
     <ds:SignatureValue>1AVSFcmgaPMFZvPHYyZDz1oFWzgiMCHI6yMfe6yCSK1pw6bkbZd/yZys8DuySi3Q75bnu3FmbrJQ 
L9eEfoXK7kJEut79f9xrBwScNYQ21AZdYh5Rdzm7jRsbugYuQpfUUWasR6U37+bStVPpsCYEo4+C 
Y1arLC/9ujj7aGxF7H+EMk7X0L4059+2v711X7a/3biowx2CyNOgjNRcrri3cyX/0soryyCA6/zH 
fO2wcQi4udMXcZwXtZpAsluah7DjGp9MSTS5NInKm3Is4VIS9fN3KmKKTJYYZI27N0lFAxgHGVXc 
GPWsh4hAd1CqQvuM0P5YlBfgPBD6Mu6tmZ9VLg==</ds:SignatureValue> 
     <ds:KeyInfo> 
     <ds:X509IssuerSerial> 
      <ds:X509IssuerName>CN=Symantec Class 3 Secure Server CA - G4,OU=Symantec Trust Network,O=Symantec Corporation,C=US</ds:X509IssuerName> 
      <ds:X509SerialNumber>142421751065451577073995987482935596892</ds:X509SerialNumber> 
     </ds:X509IssuerSerial> 
     <ds:X509Data> 
      <ds:X509Certificate>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 
TyU0Bbc2VGLlcP8=</ds:X509Certificate> 
     </ds:X509Data> 
     </ds:KeyInfo> 
    </ds:Signature> 
    <saml:Subject> 
     <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified">C229699</saml:NameID> 
     <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> 
     <saml:SubjectConfirmationData InResponseTo="63622fa6-9a00-4d39-9c92-791c3a1efc3f" NotOnOrAfter="2017-12-04T13:57:30Z" Recipient="http://my-app.net/saml"/> 
     </saml:SubjectConfirmation> 
    </saml:Subject> 
    <saml:Conditions NotBefore="2017-12-04T13:42:30Z" NotOnOrAfter="2017-12-04T13:57:30Z"> 
     <saml:AudienceRestriction> 
     <saml:Audience>http://my-app.net</saml:Audience> 
     </saml:AudienceRestriction> 
    </saml:Conditions> 
    <saml:AuthnStatement AuthnInstant="2017-12-04T13:47:30Z" SessionIndex="gkifgihgclegelojncjfgegcddfncgdaefcjgbod"> 
     <saml:AuthnContext> 
     <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef> 
     </saml:AuthnContext> 
    </saml:AuthnStatement> 
    <saml:AttributeStatement> 
     <saml:Attribute Name="UserID" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> 
     <saml:AttributeValue>D100000</saml:AttributeValue> 
     </saml:Attribute> 
    </saml:AttributeStatement> 
    </saml:Assertion> 
</samlp:Response> 

Đó là một yêu cầu rằng đó là một thực hiện thủ công nhắm mục tiêu netcoreapp2.0 vì vậy tôi đã cố gắng để đưa ra các hợp giải pháp để xác thực giá trị Chữ ký đang được cung cấp. Tài liệu này, How to: Verify the Digital Signatures of XML Documents, hữu ích trong việc giải thích một số quy trình nhưng việc triển khai SSO của tôi yêu cầu xác thực thêm.

Để kéo dạng xml từ Hồi đáp SAML Tôi có đoạn như sau:

var samlResponse = Request.Form["SAMLResponse"]; 
var toBytes = Convert.FromBase64String(samlResponse); 
string decodedString = 
Encoding.UTF8.GetString(toBytes); 

Chỉ cần cho một tài liệu tham khảo nhanh chóng mà không cần mở liên kết ở trên đây là những gì mã trông giống như (sử dụng giá trị mẫu của tôi/biến nếu có):

CspParameters cspParams = new CspParameters(); 
cspParams.KeyContainerName = "XML_DSIG_RSA_KEY"; 

// Create a new RSA signing key and save it in the container. 
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams); 

// Create a new XML document. 
XmlDocument xmlDoc = new XmlDocument(); 

// Load an XML file into the XmlDocument object. 
xmlDoc.PreserveWhitespace = true; 
xmlDoc.LoadXml(decodedString); 

// Verify the signature of the signed XML. 
Console.WriteLine("Verifying signature..."); 
bool result = VerifyXml(xmlDoc, rsaKey); 

// Display the results of the signature verification to 
// the console. 
if (result) 
{ 
    Console.WriteLine("The XML signature is valid."); 
} 
else 
{ 
    Console.WriteLine("The XML signature is not valid."); 
} 

public static Boolean VerifyXml(XmlDocument Doc, RSA Key) 
{ 
    // Check arguments. 
    if (Doc == null) 
     throw new ArgumentException("Doc"); 
    if (Key == null) 
     throw new ArgumentException("Key"); 

    // Create a new SignedXml object and pass it 
    // the XML document class. 
    SignedXml signedXml = new SignedXml(Doc); 

    // Find the "Signature" node and create a new 
    // XmlNodeList object. 
    XmlNodeList nodeList = Doc.GetElementsByTagName("Signature"); 

    // Throw an exception if no signature was found. 
    if (nodeList.Count <= 0) 
    { 
     throw new CryptographicException("Verification failed: No Signature was found in the document."); 
    } 

    // This example only supports one signature for 
    // the entire XML document. Throw an exception 
    // if more than one signature was found. 
    if (nodeList.Count >= 2) 
    { 
     throw new CryptographicException("Verification failed: More that one signature was found for the document."); 
    } 

    // Load the first <signature> node. 
    signedXml.LoadXml((XmlElement)nodeList[0]); 

    // Check the signature and return the result. 
    return signedXml.CheckSignature(Key); 
} 

UPDATE: giải pháp công tác để thực hiện thủ công của tôi SAML SSO trong Asp.Net lõi 2.0: Trước tiên tôi có các phương pháp dưới đây có tên là "VerifyXml" để xác minh chữ ký của tài liệu Xml đó là lấy lại ed từ dữ liệu biểu mẫu phản hồi SAML. Sau đó, tôi xác minh Chứng chỉ X509 trong mã AccountController của mình là @Evk (nhờ một lần nữa giúp đỡ) chỉ ra rằng việc xác minh chữ ký là không đủ, trong trường hợp này, để ngăn chặn các Phản hồi SAML tùy ý được gửi và chấp nhận. Ngoài việc xác minh hai giá trị đó, trong trường hợp của tôi, tôi cũng cần phải xác thực tham số "InResponseTo" khớp với giá trị được tạo bởi ứng dụng web của tôi (SP) trong một khoảng thời gian hợp lý. Nói chung, đăng nhập không mất nhiều thời gian để bạn có thể tạo một tác vụ để quên ID AuthnRequest đã được tạo và phát hành bởi ứng dụng web của bạn sau một khoảng thời gian nhất định; nói một phút hoặc một khoảng thời gian phù hợp với bạn (Không bao gồm mã này trong câu trả lời).

public static bool VerifyXml(XmlDocument Doc) 
{ 
    // Check document isn't null. 
    if (Doc == null) 
     throw new ArgumentException("Doc");  
    SignedXml signedXml = new SignedXml(Doc); 
    var nsManager = new XmlNamespaceManager(Doc.NameTable); 
    nsManager.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#"); 
    var node = Doc.SelectSingleNode("//ds:Signature", nsManager); 
    signedXml.LoadXml((XmlElement)node); 
    return signedXml.CheckSignature(); 
} 
/* ******* CONTROLLER CODE ******* */ 
SignedXml signedXml = new SignedXml(xdoc); 
var nsManager = new XmlNamespaceManager(xdoc.NameTable); 
nsManager.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#"); 
var certElement = xdoc.SelectSingleNode("//ds:X509Certificate", nsManager); 
/* Convert the received X509 Certificate into a new X509Certificate2 object. */ 
var certReceived = new X509Certificate2(Convert.FromBase64String(certElement.InnerText)); 
/* Load the pre-shared X509 Certificate from the idP metadata file. I have it stored in a secure database (You DO NOT want this stored in an easily accessible place, especially for production, in the project as it contains sensitive information). */ 
var loadSafeCert = _context.StoredMetadata.Where(metadata => idPMetadata.Certificate == "Certificate").FirstOrDefault(); 
/* Create a new X509Certificate2 using the value of the pre-defined certificate. */  
var safeCertificate = new X509Certificate2(Convert.FromBase64String(loadSafeCert.ConfigurationValue));  
/* Compare the received X509 Certificate value vs the pre-defined X509 Certificate value to ensure the validity. */ 
if (certReceived.GetPublicKeyString() == safeCertificate.GetPublicKeyString()) 
{ /* Store/get attributes, authenticate user, etc here */ } 
+0

Vì vậy, bạn đã thử mã đó trên phản hồi xml chưa? – Evk

+0

Vâng tôi đã thử nó trên nó và tôi vẫn không thể có được xác nhận để trở về sự thật. Ngoài ra, tôi đã cập nhật câu hỏi của mình để bao gồm cách tôi chuyển đổi dữ liệu Biểu mẫu phản hồi thành chuỗi trước khi tôi thử đoạn mã đó để làm rõ cách tôi đã cố gắng sử dụng. – Jared

+0

Khó để đề xuất nhiều, bởi vì SignedXml là cách để đi trong trường hợp này.Tại sao nó trả về false là khó để nói mà không có phản hồi mẫu saml (với chữ ký và tất cả các thứ khác mà bạn đã thay thế bằng XXX - điều này không thực sự cần thiết vì tôi không nghĩ đó là dữ liệu nhạy cảm). Lưu ý phụ: tại sao bạn sử dụng UrlDecode nếu giá trị đã có trong base64? Có vẻ như không cần thiết. – Evk

Trả lời

2

Cố gắng xác minh chữ ký như thế này (bạn không xác minh đối với tôi, nhưng điều đó có thể được gây ra bởi những thay đổi thực hiện trong khi đăng nó ở đây):

public static bool VerifyXml(XmlDocument Doc) { 
    if (Doc == null) 
     throw new ArgumentException("Doc"); 
    SignedXml signedXml = new SignedXml(Doc); 
    var nsManager = new XmlNamespaceManager(Doc.NameTable); 
    nsManager.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#"); 
    var node = Doc.SelectSingleNode("//ds:Signature", nsManager); 
    // find signature node 
    var certElement = Doc.SelectSingleNode("//ds:X509Certificate", nsManager); 
    // find certificate node 
    var cert = new X509Certificate2(Convert.FromBase64String(certElement.InnerText));    
    signedXml.LoadXml((XmlElement)node); 
    return signedXml.CheckSignature(cert); 
} 

Nếu điều đó không làm việc, cũng cố gắng giống nhau nhưng gọi

return signedXml.CheckSignature(); 

thay vì

return signedXml.CheckSignature(cert); 

Lưu ý rằng việc xác minh chữ ký này không đủ để đảm bảo rằng phản hồi không bị giả mạo. Bạn xác minh chữ ký bằng cách sử dụng khóa được cung cấp trong phản hồi (X509Data), có nghĩa là kẻ tấn công có thể đã chặn phản hồi, trích xuất thông tin và từ bỏ nó bằng khóa riêng của mình, vì vậy chữ ký sẽ hợp lệ, nhưng khóa nó đã được ký kết sẽ không được. Vì vậy, sau khi trích xuất chứng chỉ (hoặc bạn có thể sử dụng phương thức signedXml.CheckSignatureReturningKey để lấy khóa công khai liên quan đến chữ ký), bạn cần phải xác minh rằng nó hợp lệ và đó là chứng chỉ bạn đang mong đợi (ví dụ bằng cách so sánh băm của nó với băm chứng chỉ bạn mong đợi).

+0

Câu trả lời đầu tiên của bạn hoạt động hoàn hảo (các tác phẩm thay thế của bạn). Cảm ơn rất nhiều vì sự giúp đỡ của bạn, đây chính xác là những gì tôi cần! – Jared

+0

@Jared nếu công trình thứ hai - sử dụng nó, nó tốt hơn (và loại bỏ mã mà tìm thấy nút chứng chỉ, vì nó không cần thiết sau đó). – Evk

+0

Sẽ cảm ơn! Chỉ vì mục đích làm rõ, bạn có thể giải thích cho tôi lý do tại sao nó là thứ hai tốt hơn? – Jared

Các vấn đề liên quan