2017-12-05 138 views
5

Bir üçüncü taraf idP (SP tarafından başlatılan) kullanılarak bir SAML SSO uygulaması gereken bir web uygulaması üzerinde çalışıyorum. Bu bir manuel uygulama var bir gereklilik netcoreapp2.0 hedeflediğindenAsp.Net Temel SAML Yanıtı İmza Doğrulaması

<?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> 

yüzden düzgün ile gelip çalışıyorlar: Şöyle ben IDP SAMLResponse alıyorum noktaya ulaştık Sağlanan İmza değerini doğrulamak için çözüm. Bu belge, How to: Verify the Digital Signatures of XML Documents, sürecin bir kısmını açıklamakta yardımcı oldu, ancak SSO'yu uygulamam daha fazla doğrulama gerektiriyor.

Aşağıdaki öbek var SAML Tepki gelen xml formu çekin:

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

Sadece bu kod benim örnek değerler/değişkenler kullanarak (neye benzediği yukarıdaki bağlantıyı açmadan hızlı başvuru durumlarda):

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); 
} 

GÜNCELLEME: Asp.Net Core SAML SSO benim manuel uygulanması için Çalışma çözüm 2.0: Öncelikle aşağıda yöntemdir Xml belgesinin imzayı doğrulamak için "VerifyXml" adında var retriev SAML Yanıt formu verisinden alındı. Daha sonra, AccountController kodumdaki X509 sertifikasını @Evk (yardım için tekrar teşekkürler) olarak doğrulayarak imzalamanın yeterli olmadığını, bu durumda SAML Yanıtlarının gönderilmesini ve kabul edilmesini önlemek için yeterli olmadığını belirtiyorum. Bu iki değeri doğrulamak üzerine, benim durumumda, "InResponseTo" parametresinin web uygulaması (SP) tarafından oluşturulan değeri makul bir süre içinde eşleştirmesi gerekiyor. Genel olarak, bir giriş uzun bir zaman almamalı, örneğin, belirli bir süre geçtikten sonra web uygulamanız tarafından oluşturulan ve yayınlanan AuthnRequest Kimliklerini unutmak için bir görev oluşturabilirsiniz; Sizin için uygun olan bir dakika veya bir zaman dilimi söyleyin (Bu kodu cevaba dahil etmediniz).

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

Yani, bu kodu xml yanıtınızda denediniz mi? – Evk

+0

Evet Bunu denedim ve hala doğrulamanın geri dönmesini sağlayamıyorum. Ayrıca, soruyu nasıl yanıtlamayı denediğimi açıklığa kavuşturmak için bu kod yığınını denemeden önce Yanıt form verisini bir dizeye dönüştürmeyi de içerecek şekilde güncelledim. – Jared

+0

Çok fazla önermek zor, SignedXml bu durumda gitmenin yolu.Niçin yanlış döndürdüğünü, örnek saml yanıtı olmadan söylemek zordur (imzayla ve XXX ile değiştirdiğiniz diğer her şeyle - gerçekten gerekli değildir, çünkü bu hassas bir veri olduğunu düşünmüyorum). Yan not: Eğer değer zaten base64 durumunda ise UrlDecode'u kullanıyorsunuz? Gerekmiyor. – Evk

cevap

2

deneyin böyle imzayı doğrulamak için (sizin için beni doğrulamaz ama buraya göndermeden ederken yapılan değişikliklerin neden olabilir):

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); 
} 

Bu işe yaramazsa, aynı çalışıyorum ama

return signedXml.CheckSignature(); 

yerine

return signedXml.CheckSignature(cert); 
012 çağrı

Bu imzanın doğrulanması, yanıtın değiştirilmediğinden emin olmak için yeterli değildir. Yanıtın kendisinde sağlanan anahtarı kullanarak imzayı doğrularsınız (X509Data), bu da saldırganın yakalanmış yanıt verebildiğini, bilgiyi çıkardığını ve kendi anahtarıyla yeniden imzalayabileceğini, böylece imzanın geçerli olacağını, ancak imzalanmadığının anahtarının olmayacağını belirtir. Sertifika aldıktan sonra (ya da imza ile ilgili genel anahtar almak için signedXml.CheckSignatureReturningKey yöntemini kullanabilirsiniz), geçerli olduğunu ve beklediğiniz sertifikanın (örneğin, beklediğiniz sertifika ile hash değerini karşılaştırarak) doğrulamanız gerekir.

+0

İlk cevabınız mükemmel çalıştı (alternatif çalışmalarınız da). Yardımınız için çok teşekkürler, tam ihtiyacım olan şey bu! – Jared

+0

@Jared ikinci çalışırsa - onu kullanın, daha iyi (ve daha sonra gerekli değildir, çünkü sertifika düğümünü bulan kodu kaldır). – Evk

+0

Teşekkür eder! Sadece açıklama amacıyla, neden ikincisinin daha iyi olduğunu açıklayabilir misiniz? – Jared

İlgili konular