Decrittografia di un token di protezione.
CardSpace fornisce agli utenti la possibilità di gestire le proprie identità digitali e, con Internet Explorer 7.0, (o altri browser che supportano Schede informazioni) i siti Web possono richiedere all’utente un'identità digitale. Questa identità è trasportata nel modulo di un token di protezione crittografato. La decrittografia del token per utilizzare le attestazioni contenute all'interno del token, può essere eseguita con la classe dell'esempio Token
. In questo argomento ne viene illustrato il token e il suo funzionamento.
Installazione del server Web
Per eseguire gli esercizi, è necessario configurare il sito Web. La configurazione viene eseguita utilizzando il file batch di installazione seguente fornito nella cartella di esempio:
Setup.bat
Per ulteriori informazioni sull’installazione del sito Web e sulla risoluzione dei problemi, vedere Installazione dei certificati di esempio di CardSpace.
Ottenimento del token.
Il codice dell’esempio Utilizzo di Windows CardSpace con Internet Explorer 7.0 illustra il codice HTML richiesto per visualizzare il selettore di identità.
File utilizzati:
Sample.htm
Il selettore di identità viene visualizzato utilizzando l'elemento <object>
o un oggetto di comportamento binario. In questo esempio vengono utilizzati l'elemento <object>
e JavaScript per richiedere il token dall'utente e visualizzarlo in <textarea>
prima di inviarlo al sito Web.
File di esempio .htm:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Sample 2</title>
<object type="application/x-informationcard" name="_xmlToken">
<param name="tokenType" value="urn:oasis:names:tc:SAML:1.0:assertion" />
<param name="issuer" value="https://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self" />
<param name="requiredClaims"
value="https://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
https://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname
https://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
https://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" />
</object>
<script language="javascript">
function GetIdentity(){
var xmltkn=document.getElementById("_xmltoken");
var thetextarea = document.getElementById("xmltoken");
thetextarea.value = xmltkn.value ;
}
</script>
</head>
<body>
<form id="form1" method="post" action="login.aspx">
<button name="go" id="go" onclick="javascript:GetIdentity();">Click here to get the token.</button>
<button type="submit">Click here to send the card to the server</button>
<textarea cols=100 rows=20 id="xmltoken" name="xmlToken" ></textarea>
</form>
</body>
</html>
Quando l’utente fa clic su Invia, il token viene inserito in un modulo nel server, dove deve essere decrittografato e verificato prima che le attestazioni possano essere utilizzate.
La pagina login.aspx
che accetta il token inserito in C#.
<%@ Page Language="C#" Debug="true" ValidateRequest="false" %>
<%@ Import Namespace="Microsoft.IdentityModel.Samples" %>
<%@ Import Namespace="Microsoft.IdentityModel.TokenProcessor" %>
<script runat="server">
protected void ShowError(string text) {
fields.Visible = false;
errors.Visible = true;
errtext.Text = text;
}
protected void Page_Load(object sender, EventArgs e) {
string xmlToken;
xmlToken = Request.Params["xmlToken"];
if (xmlToken == null || xmlToken.Equals(""))
ShowError("Token presented was null");
else
{
Token token = new Token (xmlToken);
givenname.Text = token.Claims[SelfIssued.GivenName];
surname.Text = token.Claims[SelfIssued.Surname];
email.Text = token.Claims[SelfIssued.EmailAddress];
uid.Text = token.UniqueID;
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Login Page</title>
</head>
<body>
<form id="form1" runat="server">
<div runat="server" id="fields">
Given Name:<asp:Label ID="givenname" runat="server" Text=""></asp:Label><br/>
Surname:<asp:Label ID="surname" runat="server" Text=""></asp:Label><br/>
Email Address:<asp:Label ID="email" runat="server" Text=""></asp:Label><br/>
Unique ID:<asp:Label ID="uid" runat="server" Text=""></asp:Label><br/>
</div>
<div runat="server" id="errors" visible="false">
Error:<asp:Label ID="errtext" runat="server" Text=""></asp:Label><br/>
</div>
</form>
</body>
</html>
La pagina login.aspx
che accetta il token inserito in VB.NET:
<%@ Page Language="VB" Debug="true" ValidateRequest="false" %>
<%@ Import Namespace="Microsoft.IdentityModel.Samples" %>
<%@ Import Namespace="Microsoft.IdentityModel.TokenProcessor" %>
<script runat="server">
Protected Sub ShowError(ByVal text As String)
fields.Visible = False
errors.Visible = True
errtext.Text = text
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
Dim xmlToken As String
xmlToken = Request.Params("xmlToken")
If xmlToken = Nothing Or xmlToken.Equals("") Then
ShowError("Token presented was null")
Else
Dim token As New Token(xmlToken)
givenname.Text = token.Claims(ClaimTypes.GivenName)
surname.Text = token.Claims(ClaimTypes.Surname)
email.Text = token.Claims(ClaimTypes.Email)
uid.Text = token.UniqueID
End If
End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Login Page</title>
</head>
<body>
<form id="form1" runat="server">
<div runat="server" id="fields">
Given Name:<asp:Label ID="givenname" runat="server" Text=""></asp:Label><br/>
Surname:<asp:Label ID="surname" runat="server" Text=""></asp:Label><br/>
Email Address:<asp:Label ID="email" runat="server" Text=""></asp:Label><br/>
Unique ID:<asp:Label ID="uid" runat="server" Text=""></asp:Label><br/>
</div>
<div runat="server" id="errors" visible="false">
Error:<asp:Label ID="errtext" runat="server" Text=""></asp:Label><br/>
</div>
</form>
</body>
</html>
La classe Token
gestisce la decrittografia, la verifica e l’estrazione delle attestazioni del token XML crittografato.
Elaborazione del token: esame del formato di crittografia XML
Il token inserito dal browser viene crittografato utilizzando la crittografia W3C XML. Il documento nel quale è illustrato lo schema è XML Encryption Syntax and Processing. Gli schemi sono Schema principale e Crittografia XML. L'esempio seguente è si riferisce a un tipico token crittografato.
<enc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
xmlns:enc="http://www.w3.org/2001/04/xmlenc#">
<enc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
</e:EncryptionMethod>
<KeyInfo>
<o:SecurityTokenReference
xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-
1.0.xsd">
<o:KeyIdentifier
ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-
1.1#ThumbprintSHA1"
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-
message-security-1.0#Base64Binary">
1H3mV/pJAlVZAst/Dt0rqbBd67g=
</o:KeyIdentifier>
</o:SecurityTokenReference>
</KeyInfo>
<e:CipherData>
<e:CipherValue>
YJHp...==</e:CipherValue>
</e:CipherData>
</e:EncryptedKey>
</KeyInfo>
<enc:CipherData>
<enc:CipherValue>
ctct...9A==</enc:CipherValue>
</enc:CipherData>
</enc:EncryptedData>
Dall'analisi delle parti costitutive dell’XML inserito, si evince che l’elemento radice è <enc:EncryptedData>
. Tale elemento contiene i tre requisiti di accesso al token.
<enc:EncryptedData>
<enc:EncryptionMethod />
<KeyInfo />
<enc:CipherData />
</enc:EncryptedData>
Il primo requisito è che <enc:EncryptionMethod>
contenga il metodo utilizzato per crittografare il token.
<enc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
In questo caso, si tratta di AES-256-cbc, un algoritmo di crittografia di chiavi simmetriche, nel quale entrambe le parti utilizzano la stessa chiave per crittografia e decrittografia. La chiave simmetrica viene generata in modo causale dal creatore ed è denominata chiave temporanea. Viene quindi crittografata e archiviata nell'elemento <e:EncryptedKey>
, racchiuso nell'elemento <KeyInfo>
.
<KeyInfo >
<e:EncryptedKey />
<e:EncryptionMethod / >
<KeyInfo />
<e:CipherData />
</e:EncryptedKey>
</KeyInfo>
È preferibile crittografare il token con un algoritmo simmetrico e inviare la chiave crittografata con il token, in quanto la crittografia asimmetrica è più lenta della crittografia simmetrica e la crittografia di dati di dimensioni superiori rispetto alla chiave con una chiave asimmetrica non è pertanto consigliabile. La crittografia della sola chiave con l'algoritmo asimmetrico riduce notevolmente la quantità di elaborazione richiesta al server.
La chiave temporanea viene crittografata con la chiave pubblica (del certificato) del componente. Il metodo di crittografia della chiave temporanea è presente nell'elemento <e:EncryptionMethod>
.
<e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
</e:EncryptionMethod>
In questo caso, l’algoritmo RSA-OAEP-MGF1P viene utilizzato per la crittografia. La chiave per questa operazione è presente nell'elemento <KeyInfo>
seguente.
<KeyInfo>
<o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-
wssecurity-secext-1.0.xsd">
<o:KeyIdentifier
ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-
1.1#ThumbprintSHA1"
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-
security-1.0#Base64Binary">
1H3mV/pJAlVZAst/Dt0rqbBd67g=
</o:KeyIdentifier>
</o:SecurityTokenReference>
</KeyInfo>
Il <o:KeyIdentifier>
consente al mittente di comunicare al componente la chiave del certificato utilizzata per crittografare la chiave simmetrica, inserendo la propria identificazione digitale (con codifica Base64) nell'elemento.
Il componente utilizza quindi la chiave privata per decrittografare i dati nell'elemento <e:CipherData>
/<e:CypherValue>
.
<e:CipherData>
<e:CipherValue>
YJHp...==</e:CipherValue>
</e:CipherData>
Dopo avere recuperato la chiave simmetrica, il token stesso viene de crittografato utilizzando la chiave simmetrica.
<enc:CipherData>
<enc:CipherValue>
ctct...9A==</enc:CipherValue>
</enc:CipherData>
Caratteristiche salienti del codice del processore del token
Per comprendere il processo di decrittografia, è opportuno tenere presente le caratteristiche salienti di tale processo di seguito riportate. Per visualizzare il processo completo, consultare il codice sorgente della classe Token
.
Il costruttore della classe Token
utilizza il metodo decryptToken
per eseguire la decrittografia dei dati XML crittografati passati nel costruttore.
private static byte[] decryptToken(string xmlToken)
Per scorrere I dati XML, viene utilizzato un XmlReader
.
XmlReader reader = new XmlTextReader(new StringReader(xmlToken));
Durante la ricerca degli elementi XML, è permessa una flessibilità molto ridotta, per consentire un’interruzione immediata nel caso di un token non valido (con l’utilizzo di ArgumentException
). Per iniziare è necessario trovare l'elemento <EncryptionMethod>
, di accesso dell'elemento Algorithm
per recuperare il metodo di crittografia del token.
if (!reader.ReadToDescendant(XmlEncryptionStrings.EncryptionMethod,
XmlEncryptionStrings.Namespace))
throw new ArgumentException("Cannot find token EncryptedMethod.");
encryptionAlgorithm = reader.GetAttribute(XmlEncryptionStrings.Algorithm).GetHashCode();
Successivamente, è necessario trovare l'elemento <EncryptionMethod>
per la chiave temporanea, ottenendo nuovamente Algorithm
, archiviato come HashCode
per una ricerca più veloce.
if (!reader.ReadToFollowing(XmlEncryptionStrings.EncryptionMethod,
XmlEncryptionStrings.Namespace))
throw new ArgumentException("Cannot find key EncryptedMethod.");
m_keyEncryptionAlgorithm = reader.GetAttribute(XmlEncryptionStrings.Algorithm).GetHashCode();
L’elemento successivo è <KeyIdentifier>
, contenente l'identificazione digitale del certificato (necessario per decifrare la chiave simmetrica), che viene estratto dalla stringa Base64.
if (!reader.ReadToFollowing(WSSecurityStrings.KeyIdentifier, WSSecurityStrings.Namespace))
throw new ArgumentException("Cannot find Key Identifier.");
reader.Read();
thumbprint = Convert.FromBase64String(reader.ReadContentAsString());
L'elemento <CypherValue>
contiene la chiave simmetrica (con codifica Base64), nel rispettivo modulo crittografato.
if (!reader.ReadToFollowing(XmlEncryptionStrings.CipherValue, XmlEncryptionStrings.Namespace))
throw new ArgumentException("Cannot find symmetric key.");
reader.Read();
symmetricKeyData = Convert.FromBase64String(reader.ReadContentAsString());
<CypherValue>
contenente l’effettivo token crittografato.
if (!reader.ReadToFollowing(XmlEncryptionStrings.CipherValue, XmlEncryptionStrings.Namespace))
throw new ArgumentException("Cannot find encrypted security token.");
reader.Read();
securityTokenData = Convert.FromBase64String(reader.ReadContentAsString());
Assicurarsi che il lettore sia chiuso per liberare le risorse.
reader.Close();
La crittografia del token di protezione è supportata da uno dei due algoritmi simmetrici (AES e Triple DES). Utilizzare l'algoritmo di crittografia URI come ricerca.
SymmetricAlgorithm alg = null;
X509Certificate2 certificate = FindCertificate(thumbprint );
foreach( int i in Aes )
if (encryptionAlgorithm == i)
{
alg= new RijndaelManaged();
break;
}
if ( null == alg )
foreach (int i in TripleDes)
if (encryptionAlgorithm == i)
{
alg = new TripleDESCryptoServiceProvider();
break;
}
if (null == alg)
throw new ArgumentException("Could not determine Symmetric Algorithm");
Per ottenere la chiave simmetrica, eseguire la decrittografia con la chiave privata.
alg.Key=(certificate.PrivateKey as RSACryptoServiceProvider).Decrypt(symmetricKeyData,true);
Utilizzo dell'algoritmo individuato, decrittografia del token con l'algoritmo simmetrico.
int ivSize = alg.BlockSize / 8;
byte[] iv = new byte[ivSize];
Buffer.BlockCopy(securityTokenData, 0, iv, 0, iv.Length);
alg.Padding = PaddingMode.ISO10126;
alg.Mode = CipherMode.CBC;
ICryptoTransform decrTransform = alg.CreateDecryptor(alg.Key, iv);
byte[] plainText = decrTransform.TransformFinalBlock(securityTokenData, iv.Length,
securityTokenData.Length iv.Length);
decrTransform.Dispose();
return plainText;
}
Deserializzazione e autenticazione del token
Per utilizzare il token incorporato, decrittografato, .NET Framework 3.0 lo deserializza (tramite il WSSecurityTokenSerializer) e autentica utilizzando SamlSecurityTokenAuthenticator. Attualmente la classe Token
supporta token SAML. Nel caso in cui siano necessari altri tipi di token, lo sviluppatore deve fornire un autenticatore per supportarlo. Dopo l’avvenuta convalida da parte dell’autenticatore, la classe Token
estrae le attestazioni in un modulo utilizzabile.
public Token(String xmlToken)
{
byte[] decryptedData = decryptToken(xmlToken);
XmlReader reader = new XmlTextReader(
new StreamReader(new MemoryStream(decryptedData), Encoding.UTF8));
m_token = (SamlSecurityToken)WSSecurityTokenSerializer.DefaultInstance.ReadToken(
reader, null);
SamlSecurityTokenAuthenticator authenticator =
new SamlSecurityTokenAuthenticator(new List<SecurityTokenAuthenticator>(
new SecurityTokenAuthenticator[]{
new RsaSecurityTokenAuthenticator(),
new X509SecurityTokenAuthenticator() }), MaximumTokenSkew);
if (authenticator.CanValidateToken(m_token))
{
ReadOnlyCollection<IAuthorizationPolicy> policies = authenticator.ValidateToken(m_token);
m_authorizationContext = AuthorizationContext.CreateDefaultAuthorizationContext(policies);
FindIdentityClaims();
}
else
{
throw new Exception("Unable to validate the token.");
}
}
Utilizzo della classe del token.
Nella tabella seguente vengono descritte le proprietà esposte dalla classe Token
che estrae le attestazioni dal token di protezione.
Name | Descrizione |
---|---|
|
ClaimSet delle attestazioni di identità del token. |
|
AuthorizationContext generata dal token. |
|
Ottiene l’UniqueID (IdentityClaim) del token. Per impostazione predefinita, vengono utilizzati PPID e la chiave pubblica dell'autorità emittente e viene generato un hash comune per creare un UniqueID. Per utilizzare un campo diverso, aggiungere la riga di codice seguente:
Sostituire il valore con l’URI per la attestazione univoca. |
|
Insieme di stringhe di sola lettura delle attestazioni del token. Fornisce supporto per una funzione di accesso delle attestazioni indicizzata.
|
|
Restituisce l’attestazione di identità dell'autorità emittente (in genere, la chiave pubblica dell'autorità emittente). |
Invia commenti su questo argomento a Microsoft.
Copyright © 2007 Microsoft Corporation. Tutti i diritti riservati.