Criar uma assinatura de URL usando C# e o framework .NET - Amazon CloudFront

Criar uma assinatura de URL usando C# e o framework .NET

Os exemplos de C# desta seção implementam um exemplo de aplicação que demonstra como criar assinaturas para distribuições privadas do CloudFront usando declarações de política padrão e personalizada. Alguns dos exemplos são as funções de utilitário com base no AWS SDK for .NET que podem ser úteis em aplicações .NET.

Você também pode criar URLs assinados e cookies usando o AWS SDK for .NET. Na Referência de API do AWS SDK for .NET, consulte os seguintes tópicos:

  • Signed URLs: Amazon.CloudFront > AmazonCloudFrontUrlSigner

  • Signed cookies: Amazon.CloudFront > AmazonCloudFrontCookieSigner

nota

A criação de uma assinatura de URL é apenas uma parte do processo de fornecimento de conteúdo privado usando um signed URL. Para obter mais informações sobre o todo o processo, consulte Usar signed URLs.

Para fazer download do código, acesse Código de assinatura em C#.

Para usar uma chave RSA no framework .NET, converta o arquivo .pem da AWS fornecido no formato XML usado pelo framework .NET.

Após a conversão, o arquivo de chave privada do RSA ficará no seguinte formato:

exemplo Chave privada do RSA no formato XML do .NET Framework

<RSAKeyValue> <Modulus> wO5IvYCP5UcoCKDo1dcspoMehWBZcyfs9QEzGi6Oe5y+ewGr1oW+vB2GPB ANBiVPcUHTFWhwaIBd3oglmF0lGQljP/jOfmXHUK2kUUnLnJp+oOBL2NiuFtqcW6h/L5lIpD8Yq+NRHg Ty4zDsyr2880MvXv88yEFURCkqEXAMPLE= </Modulus> <Exponent>AQAB</Exponent> <P> 5bmKDaTz npENGVqz4Cea8XPH+sxt+2VaAwYnsarVUoSBeVt8WLloVuZGG9IZYmH5KteXEu7fZveYd9UEXAMPLE== </P> <Q> 1v9l/WN1a1N3rOK4VGoCokx7kR2SyTMSbZgF9IWJNOugR/WZw7HTnjipO3c9dy1Ms9pUKwUF4 6d7049EXAMPLE== </Q> <DP> RgrSKuLWXMyBH+/l1Dx/I4tXuAJIrlPyo+VmiOc7b5NzHptkSHEPfR9s1 OK0VqjknclqCJ3Ig86OMEtEXAMPLE== </DP> <DQ> pjPjvSFw+RoaTu0pgCA/jwW/FGyfN6iim1RFbkT4 z49DZb2IM885f3vf35eLTaEYRYUHQgZtChNEV0TEXAMPLE== </DQ> <InverseQ> nkvOJTg5QtGNgWb9i cVtzrL/1pFEOHbJXwEJdU99N+7sMK+1066DL/HSBUCD63qD4USpnf0myc24in0EXAMPLE==</InverseQ> <D> Bc7mp7XYHynuPZxChjWNJZIq+A73gm0ASDv6At7F8Vi9r0xUlQe/v0AQS3ycN8QlyR4XMbzMLYk 3yjxFDXo4ZKQtOGzLGteCU2srANiLv26/imXA8FVidZftTAtLviWQZBVPTeYIA69ATUYPEq0a5u5wjGy UOij9OWyuEXAMPLE= </D> </RSAKeyValue>

O seguinte código C# cria um URL assinado que usa uma política padrão executando as seguintes etapas:

  • Cria uma declaração de política.

  • Adiciona hash à declaração de política usando SHA1 e assina o resultado usando RSA e a chave privada com a chave pública correspondente que está em um grupo de chaves confiáveis.

  • Codifica em base64 a declaração de política assinada e com hash e substitui os caracteres especiais para tornar a string segura para ser usada como parâmetro de solicitação de URL.

  • Concatena os valores.

Para obter a implementação completa, consulte o exemplo em Código de assinatura em C#.

exemplo Método de assinatura de política padrão em C#

public static string ToUrlSafeBase64String(byte[] bytes) { return System.Convert.ToBase64String(bytes) .Replace('+', '-') .Replace('=', '_') .Replace('/', '~'); } public static string CreateCannedPrivateURL(string urlString, string durationUnits, string durationNumber, string pathToPolicyStmnt, string pathToPrivateKey, string privateKeyId) { // args[] 0-thisMethod, 1-resourceUrl, 2-seconds-minutes-hours-days // to expiration, 3-numberOfPreviousUnits, 4-pathToPolicyStmnt, // 5-pathToPrivateKey, 6-PrivateKeyId TimeSpan timeSpanInterval = GetDuration(durationUnits, durationNumber); // Create the policy statement. string strPolicy = CreatePolicyStatement(pathToPolicyStmnt, urlString, DateTime.Now, DateTime.Now.Add(timeSpanInterval), "0.0.0.0/0"); if ("Error!" == strPolicy) return "Invalid time frame." + "Start time cannot be greater than end time."; // Copy the expiration time defined by policy statement. string strExpiration = CopyExpirationTimeFromPolicy(strPolicy); // Read the policy into a byte buffer. byte[] bufferPolicy = Encoding.ASCII.GetBytes(strPolicy); // Initialize the SHA1CryptoServiceProvider object and hash the policy data. using (SHA1CryptoServiceProvider cryptoSHA1 = new SHA1CryptoServiceProvider()) { bufferPolicy = cryptoSHA1.ComputeHash(bufferPolicy); // Initialize the RSACryptoServiceProvider object. RSACryptoServiceProvider providerRSA = new RSACryptoServiceProvider(); XmlDocument xmlPrivateKey = new XmlDocument(); // Load PrivateKey.xml, which you created by converting your // .pem file to the XML format that the .NET framework uses. // Several tools are available. xmlPrivateKey.Load(pathToPrivateKey); // Format the RSACryptoServiceProvider providerRSA and // create the signature. providerRSA.FromXmlString(xmlPrivateKey.InnerXml); RSAPKCS1SignatureFormatter rsaFormatter = new RSAPKCS1SignatureFormatter(providerRSA); rsaFormatter.SetHashAlgorithm("SHA1"); byte[] signedPolicyHash = rsaFormatter.CreateSignature(bufferPolicy); // Convert the signed policy to URL-safe base64 encoding and // replace unsafe characters + = / with the safe characters - _ ~ string strSignedPolicy = ToUrlSafeBase64String(signedPolicyHash); // Concatenate the URL, the timestamp, the signature, // and the key pair ID to form the signed URL. return urlString + "?Expires=" + strExpiration + "&Signature=" + strSignedPolicy + "&Key-Pair-Id=" + privateKeyId; } }

O seguinte código C# cria um URL assinado que usa uma política personalizada executando as seguintes etapas:

  1. Cria uma declaração de política.

  2. Codifica a declaração de política em base64 e substitui os caracteres especiais para tornar a string segura para ser usada como parâmetro de solicitação de URL.

  3. Adiciona hash a declaração de política usando SHA1 e criptografa o resultado usando RSA e a chave privada com a chave pública correspondente que está em um grupo de chaves confiáveis.

  4. Codifica em base64 a declaração de política com hash e substitui os caracteres especiais para tornar a string segura para ser usada como parâmetro de solicitação de URL.

  5. Concatena os valores.

Para obter a implementação completa, consulte o exemplo em Código de assinatura em C#.

exemplo Método de assinatura de política personalizada em C#

public static string ToUrlSafeBase64String(byte[] bytes) { return System.Convert.ToBase64String(bytes) .Replace('+', '-') .Replace('=', '_') .Replace('/', '~'); } public static string CreateCustomPrivateURL(string urlString, string durationUnits, string durationNumber, string startIntervalFromNow, string ipaddress, string pathToPolicyStmnt, string pathToPrivateKey, string PrivateKeyId) { // args[] 0-thisMethod, 1-resourceUrl, 2-seconds-minutes-hours-days // to expiration, 3-numberOfPreviousUnits, 4-starttimeFromNow, // 5-ip_address, 6-pathToPolicyStmt, 7-pathToPrivateKey, 8-privateKeyId TimeSpan timeSpanInterval = GetDuration(durationUnits, durationNumber); TimeSpan timeSpanToStart = GetDurationByUnits(durationUnits, startIntervalFromNow); if (null == timeSpanToStart) return "Invalid duration units." + "Valid options: seconds, minutes, hours, or days"; string strPolicy = CreatePolicyStatement( pathToPolicyStmnt, urlString, DateTime.Now.Add(timeSpanToStart), DateTime.Now.Add(timeSpanInterval), ipaddress); // Read the policy into a byte buffer. byte[] bufferPolicy = Encoding.ASCII.GetBytes(strPolicy); // Convert the policy statement to URL-safe base64 encoding and // replace unsafe characters + = / with the safe characters - _ ~ string urlSafePolicy = ToUrlSafeBase64String(bufferPolicy); // Initialize the SHA1CryptoServiceProvider object and hash the policy data. byte[] bufferPolicyHash; using (SHA1CryptoServiceProvider cryptoSHA1 = new SHA1CryptoServiceProvider()) { bufferPolicyHash = cryptoSHA1.ComputeHash(bufferPolicy); // Initialize the RSACryptoServiceProvider object. RSACryptoServiceProvider providerRSA = new RSACryptoServiceProvider(); XmlDocument xmlPrivateKey = new XmlDocument(); // Load PrivateKey.xml, which you created by converting your // .pem file to the XML format that the .NET framework uses. // Several tools are available. xmlPrivateKey.Load("PrivateKey.xml"); // Format the RSACryptoServiceProvider providerRSA // and create the signature. providerRSA.FromXmlString(xmlPrivateKey.InnerXml); RSAPKCS1SignatureFormatter RSAFormatter = new RSAPKCS1SignatureFormatter(providerRSA); RSAFormatter.SetHashAlgorithm("SHA1"); byte[] signedHash = RSAFormatter.CreateSignature(bufferPolicyHash); // Convert the signed policy to URL-safe base64 encoding and // replace unsafe characters + = / with the safe characters - _ ~ string strSignedPolicy = ToUrlSafeBase64String(signedHash); return urlString + "?Policy=" + urlSafePolicy + "&Signature=" + strSignedPolicy + "&Key-Pair-Id=" + PrivateKeyId; } }

exemplo Métodos utilitários para geração de assinaturas

Os métodos a seguir obtêm a declaração de política de um arquivo e analisam os intervalos de tempo para a geração de assinatura.

public static string CreatePolicyStatement(string policyStmnt, string resourceUrl, DateTime startTime, DateTime endTime, string ipAddress) { // Create the policy statement. FileStream streamPolicy = new FileStream(policyStmnt, FileMode.Open, FileAccess.Read); using (StreamReader reader = new StreamReader(streamPolicy)) { string strPolicy = reader.ReadToEnd(); TimeSpan startTimeSpanFromNow = (startTime - DateTime.Now); TimeSpan endTimeSpanFromNow = (endTime - DateTime.Now); TimeSpan intervalStart = (DateTime.UtcNow.Add(startTimeSpanFromNow)) - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); TimeSpan intervalEnd = (DateTime.UtcNow.Add(endTimeSpanFromNow)) - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); int startTimestamp = (int)intervalStart.TotalSeconds; // START_TIME int endTimestamp = (int)intervalEnd.TotalSeconds; // END_TIME if (startTimestamp > endTimestamp) return "Error!"; // Replace variables in the policy statement. strPolicy = strPolicy.Replace("RESOURCE", resourceUrl); strPolicy = strPolicy.Replace("START_TIME", startTimestamp.ToString()); strPolicy = strPolicy.Replace("END_TIME", endTimestamp.ToString()); strPolicy = strPolicy.Replace("IP_ADDRESS", ipAddress); strPolicy = strPolicy.Replace("EXPIRES", endTimestamp.ToString()); return strPolicy; } } public static TimeSpan GetDuration(string units, string numUnits) { TimeSpan timeSpanInterval = new TimeSpan(); switch (units) { case "seconds": timeSpanInterval = new TimeSpan(0, 0, 0, int.Parse(numUnits)); break; case "minutes": timeSpanInterval = new TimeSpan(0, 0, int.Parse(numUnits), 0); break; case "hours": timeSpanInterval = new TimeSpan(0, int.Parse(numUnits), 0 ,0); break; case "days": timeSpanInterval = new TimeSpan(int.Parse(numUnits),0 ,0 ,0); break; default: Console.WriteLine("Invalid time units;" + "use seconds, minutes, hours, or days"); break; } return timeSpanInterval; } private static TimeSpan GetDurationByUnits(string durationUnits, string startIntervalFromNow) { switch (durationUnits) { case "seconds": return new TimeSpan(0, 0, int.Parse(startIntervalFromNow)); case "minutes": return new TimeSpan(0, int.Parse(startIntervalFromNow), 0); case "hours": return new TimeSpan(int.Parse(startIntervalFromNow), 0, 0); case "days": return new TimeSpan(int.Parse(startIntervalFromNow), 0, 0, 0); default: return new TimeSpan(0, 0, 0, 0); } } public static string CopyExpirationTimeFromPolicy(string policyStatement) { int startExpiration = policyStatement.IndexOf("EpochTime"); string strExpirationRough = policyStatement.Substring(startExpiration + "EpochTime".Length); char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; List<char> listDigits = new List<char>(digits); StringBuilder buildExpiration = new StringBuilder(20); foreach (char c in strExpirationRough) { if (listDigits.Contains(c)) buildExpiration.Append(c); } return buildExpiration.ToString(); }

Consulte também