2016-04-27 1 views
0

У меня есть общедоступный веб-крючок, который вызывается службой для отправки уведомлений на моем сайте. В этом веб-крюке я ожидаю зашифрованный токен. Когда я получаю токен, я дешифрую его с помощью предопределенного ключа и проверяю, что токен - это то, что я ожидал. Это прекрасно работает.Как предотвратить исключение, когда код не может быть расшифрован?

Если в функцию передан незашифрованный или плохой токен, дешифрование, конечно, завершится неудачей. Это нормально, , но я не хочу, чтобы генерируемое исключение, когда это произойдет. Если какой-то хакер создает 1 000 000 неудачных запросов против моего веб-крючка за секунду, и каждый запрос занимает 1 секунду, чтобы обработать огромное исключение, это приведет к сбою моего сервера.

Вот мой код дешифрования до сих пор:

public static string Decrypt(string cipherText, string key) 
    { 
     string EncryptionKey = key; 
     cipherText = cipherText.Replace(" ", "+"); 

     //I added this to prevent exception when trying to Convert.FromBase64String() 
     if (cipherText.Length % 4 != 0) 
     { 
      //cipherText must be a length that is a multiple of 4, otherwise it will fail 
      return null; 
     } 

     byte[] cipherBytes = Convert.FromBase64String(cipherText); 
     using (Aes encryptor = Aes.Create()) 
     { 
      Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 }); 
      encryptor.Key = pdb.GetBytes(32); 
      encryptor.IV = pdb.GetBytes(16); 
      using (MemoryStream ms = new MemoryStream()) 
      { 
       using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write)) 
       { 
        cs.Write(cipherBytes, 0, cipherBytes.Length); 
        cs.Close(); //currently giving exception HERE 
       } 
       cipherText = Encoding.Unicode.GetString(ms.ToArray()); 
      } 
     } 
     return cipherText; 
    } 

Это дает мне исключение в cs.Close() The input data is not a complete block, когда я намеренно передать в незашифрованном строку. Я не уверен, что именно здесь проверяется, поэтому я не знаю, как его предотвратить.

Как я могу реорганизовать этот код, чтобы, если строка не может быть расшифрована, это не вызовет исключения?

+0

Я думаю, вам нужно убедиться, что ваша длина 'cipherBytes' делится на' encryptor.BlockSize'. Это может раздражать, если вы пытаетесь обрабатывать поток данных. Но если вы просто берете строку, это не должно быть проблемой. –

+0

Если вы позволите хакеру создать 1 000 000 плохих запросов и по-прежнему ничего не предпринимать, чтобы остановить его, то вы уже сделали что-то ужасно неправильно. – NullUserException

ответ

3

Исключение составляет catch и делайте с ним то, что вы хотите. (журнал, перенаправление, игнорирование и т. д.). Документацию Try/catch можно найти здесь: https://msdn.microsoft.com/en-us/library/0yd65esw.aspx

+0

Мне известно о попытке/уловке, но я подумал, что если я «поймаю» исключение, то это не решит мою проблему «Если какой-то хакер создает 1 000 000 плохих запросов против моего веб-крючка за секунду, и каждый запрос занимает 1 секунду обработать огромное исключение, это приведет к сбою моего сервера ». ?? – AlbatrossCafe

+0

@AlbatrossCafe Это правильный способ справиться с этим. Конечно, вы можете подорвать крипто API и сами обрабатывать вещи, чтобы он не генерировал исключение, но затем вы попадаете в еще более опасную территорию: (повторная) реализация криптографии. Это намного хуже. Просто обработайте исключение, как и следовало, и выполните ограничение скорости, чтобы предотвратить описанный сценарий. – NullUserException

0

Когда вы расшифровываете зашифрованный текст с не аутентифицированным режимом, например CBC, ошибка заполнения может обнаружить неправильный ключ или неправильный конечный блок с вероятностью примерно 255 раз 256 раз , Это происходит, когда последний блок поврежден и не может быть найдено допустимое дополнение. PKCS#7 padding используется по умолчанию и имеет специальную структуру, которая может быть проверена.

Вы можете запросить дешифратор не пытаться unpadding каким-либо образом с:

encryptor.Padding = PaddingMode.None; 

, но тогда вы должны unpad себя (обивка байт может быть только в диапазоне от 1 до 16 для AES):

var ctBytes = ms.ToArray(); 
var last = ctBytes[ctBytes.Length-1]; 
if (last < 17 && last > 0) { 
    cipherText = Encoding.Unicode.GetString(ctBytes.Take(ctBytes.Length - last)); 
} else { 
    ciphertext = null; 
}