ВСТУПЛЕНИЕ

Спасибо, что прочитали этот пост об освоении аутентификации в .NET! Это только первая часть нашей серии, и у нас есть более интересные темы для обсуждения в будущем. В части 2 мы углубимся в методы безопасного хеширования паролей, а затем обсудим безопасное хранение паролей с помощью Entity Framework Core в части 3. Часть 4 посвящена внедрению шифрования и дешифрования для аутентификации пользователей, а Часть 5 посвящена передовым методам повышения безопасности.

Если вы хотите быть в курсе наших последних публикаций и узнать больше об освоении аутентификации в .NET, обязательно подпишитесьна наш блог и следите за нашими обновлениями. Мы рады поделиться с вами новыми советами и рекомендациями по мере изучения мира аутентификации в .NET!

Что такое аутентификация?

Аутентификация — это процесс подтверждения личности пользователя, устройства или системы, пытающихся получить доступ к защищенному ресурсу. В веб-приложениях аутентификация часто предполагает предоставление пользователями своих учетных данных (обычно это имя пользователя и пароль) для аутентификации своей личности. Безопасная аутентификация имеет решающее значение для защиты конфиденциальных данных и предотвращения несанкционированного доступа к вашему приложению.

Важность безопасной аутентификации

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

В этом посте мы рассмотрим, как использовать шифрование и дешифрование паролей для обеспечения безопасной аутентификации в .NET 6, которая также совместима с .NET 7. Entity Framework Core также будет рассмотрен для безопасной вставки и извлечения данных.

Шифрование и расшифровка пароля

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

Процесс шифрования и расшифровки пароля:

Шифрование и дешифрование паролей влекут за собой преобразование обычного текстового пароля в зашифрованное представление. Когда человек входит в систему, введенный им пароль шифруется и сравнивается с сохраненным зашифрованным паролем. Пользователю предоставляется доступ, если два зашифрованных пароля совпадают.

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

Важность шифрования и дешифрования паролей в современных системах аутентификации:

Шифрование и расшифровка паролей имеют решающее значение для защиты пользовательских данных и обеспечения того, чтобы только авторизованные пользователи имели доступ к системе. Использование надежных методов шифрования, таких как хеширование с солью, и постоянное обновление методов шифрования для устранения новых угроз безопасности являются передовыми методами шифрования и дешифрования паролей.

Алгоритмы симметричного шифрования

2.1 AES (расширенный стандарт шифрования)

AES — это популярный алгоритм симметричного шифрования с мощными функциями шифрования и декодирования. Он работает с блоками данных фиксированного размера и поддерживает ключи размером 128, 192 или 256 бит. Он эффективен, но требует тщательного управления ключами, поскольку он использует один и тот же ключ как для шифрования, так и для дешифрования.

Как это работает ?

Шифрование AES:

  1. Расширение ключа. Исходный ключ шифрования расширяется на несколько отдельных ключей цикла, по одному на каждый этап шифрования.
  2. Начальный раунд: открытый текст делится на блоки по 128 бит и подвергается операции XOR с ключом первого раунда.
  3. Раунды. Открытый текст проходит серию замен, перестановок и линейных преобразований, которые повторяются фиксированное количество раз (10, 12 или 14 раз в зависимости от размера ключа). В каждом раунде используется другой ключ раунда, который генерируется из исходного ключа на этапе расширения ключа.
  4. Финальный раунд. Финальный раунд аналогичен другим раундам, но без шага замены.
  5. Зашифрованный текст. Полученный зашифрованный текст представляет собой зашифрованную версию открытого текста, которую можно расшифровать только с помощью того же ключа, который использовался для шифрования.

Расшифровка AES:

  1. Расширение ключа. Ключ дешифрования получается из исходного ключа шифрования с помощью процесса, называемого обратным расширением ключа.
  2. Начальный раунд: зашифрованный текст делится на блоки по 128 бит и подвергается операции XOR с ключом последнего раунда.
  3. Раунды. Зашифрованный текст проходит серию обратных замен, перестановок и линейных преобразований, которые повторяются в порядке, обратном процессу шифрования. В каждом раунде используется другой ключ раунда, который генерируется из ключа дешифрования на этапе обратного раскрытия ключа.
  4. Финальный раунд. Финальный раунд аналогичен другим раундам, но без шага обратной замены.
  5. Открытый текст. Полученный открытый текст представляет собой расшифрованную версию зашифрованного текста, то есть исходного открытого текста, зашифрованного тем же ключом.

Шифрование и дешифрование AES являются симметричными операциями, что означает, что один и тот же ключ используется как для шифрования, так и для дешифрования. Выбор размера ключа (128, 192 или 256 бит) определяет надежность шифрования, при этом ключи большего размера обеспечивают большую безопасность, но более низкую производительность.

Вот пример использования AES для шифрования и дешифрования в .NET:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class AesExample
{
    public static void Main()
    {
        string original = "This is a sample text to be encrypted";

        using (Aes myAes = Aes.Create())
        {
            byte[] encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV);
            string decrypted = DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV);

            Console.WriteLine($"Original: {original}");
            Console.WriteLine($"Encrypted: {BitConverter.ToString(encrypted)}");
            Console.WriteLine($"Decrypted: {decrypted}");
        }
    }

    static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
    {
        byte[] encrypted;

        using (Aes aesAlg = Aes.Create())
        {
            aesAlg.Key = Key;
            aesAlg.IV = IV;

            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        swEncrypt.Write(plainText);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }

        return encrypted;
    }

    static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
    {
        string decrypted;

        using (Aes aesAlg = Aes.Create())
        {
            aesAlg.Key = Key;
            aesAlg.IV = IV;

            ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

            using (MemoryStream msDecrypt = new MemoryStream(cipherText))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {
                        decrypted = srDecrypt.ReadToEnd();
                    }
                }
            }
        }

        return decrypted;
    }
}

2.2 DES (стандарт шифрования данных)

Американский федеральный стандарт, известный как стандарт шифрования данных (DES), был создан как блочный шифр с симметричным ключом в 1970-х годах. Он медленнее и менее безопасен, чем современные методы шифрования, такие как AES, поскольку использует только 56-битный ключ и 64-битный размер блока. Так что интересно посмотреть, как DES можно применить в .NET, чтобы понять историю криптографии и в образовательных целях.

Как это работает?

DES-шифрование:

  1. Генерация ключа. Исходный ключ шифрования уменьшается с 64 до 56 бит за счет отбрасывания каждого восьмого бита.
  2. Расширение ключа. Сокращенный ключ используется для создания 16 ключей цикла, по одному на каждый этап шифрования.
  3. Начальная перестановка. Открытый текст делится на блоки по 64 бита и подвергается начальной перестановке.
  4. Раунды: открытый текст проходит серию операций замены и перестановки, которые повторяются 16 раз. В каждом раунде используется другой ключ раунда, сгенерированный на этапе расширения ключа.
  5. Окончательная перестановка. Полученный зашифрованный текст подвергается окончательной перестановке перед передачей или безопасным хранением.

Расшифровка DES:

  1. Генерация ключа. Исходный ключ шифрования уменьшается с 64 до 56 бит за счет отбрасывания каждого восьмого бита.
  2. Расширение ключа. Сокращенный ключ используется для создания 16 ключей раундов, по одному на каждый раунд шифрования. Круглые ключи используются в обратном порядке для расшифровки.
  3. Начальная перестановка: зашифрованный текст делится на блоки по 64 бита и подвергается начальной перестановке.
  4. Раунды. Зашифрованный текст проходит серию обратных операций замены и перестановки, которые повторяются 16 раз в порядке, обратном процессу шифрования. В каждом раунде используется другой ключ раунда, сгенерированный на этапе расширения ключа.
  5. Окончательная перестановка. Полученный открытый текст подвергается окончательной перестановке для получения исходного открытого текста, который был зашифрован.

Вот пример использования DES для шифрования и расшифровки данных в .NET:

  1. Установите необходимый пакет:
dotnet add package System.Security.Cryptography.Algorithms

2. Создайте служебный класс для шифрования и дешифрования DES:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public static class DESUtility
{
    public static byte[] Encrypt(string data, byte[] key, byte[] iv)
    {
        using var des = DES.Create();
        des.Key = key;
        des.IV = iv;

        using var encryptor = des.CreateEncryptor();
        byte[] encryptedData;

        using (var ms = new MemoryStream())
        {
            using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
            {
                using (var sw = new StreamWriter(cs, Encoding.UTF8))
                {
                    sw.Write(data);
                }
                encryptedData = ms.ToArray();
            }
        }

        return encryptedData;
    }

    public static string Decrypt(byte[] encryptedData, byte[] key, byte[] iv)
    {
        using var des = DES.Create();
        des.Key = key;
        des.IV = iv;

        using var decryptor = des.CreateDecryptor();
        string decryptedData;

        using (var ms = new MemoryStream(encryptedData))
        {
            using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
            {
                using (var sr = new StreamReader(cs, Encoding.UTF8))
                {
                    decryptedData = sr.ReadToEnd();
                }
            }
        }

        return decryptedData;
    }
}

3. Используйте служебный класс для шифрования и расшифровки данных:

string data = "Hello, World!";
byte[] key = new byte[8] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
byte[] iv = new byte[8] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };

byte[] encryptedData = DESUtility.Encrypt(data, key, iv);
Console.WriteLine($"Encrypted data: {Convert.ToBase64String(encryptedData)}");

string decryptedData = DESUtility.Decrypt(encryptedData, key, iv);
Console.WriteLine($"Decrypted data: {decryptedData}");

Обратите внимание, что DES не рекомендуется для использования в современных приложениях, так как он считается небезопасным. Он просто предоставляется здесь в образовательных целях. Вместо этого используйте для своих проектов AES или другие более надежные методы шифрования.

Алгоритмы асимметричного шифрования

3.1 RSA (Ривест-Шамир-Адлеман)

Алгоритмы асимметричного шифрования, такие как RSA (Rivest-Shamir-Adleman), популярны и считаются одним из самых безопасных способов защиты данных. Открытый ключ используется для шифрования, а закрытый ключ используется для расшифровки. В этой части мы рассмотрим, как использовать шифрование RSA в вашем проекте .NET, и предоставим пример кода.

Как это работает?

Шифрование RSA:

  1. Генерация ключа. Пара открытого и закрытого ключей генерируется с использованием математического алгоритма. Открытый ключ предоставляется всем, кто хочет отправлять зашифрованные сообщения, а закрытый ключ хранится в секрете.
  2. Шифрование обычного текста: текстовое сообщение преобразуется в числовое значение с помощью обратимого процесса, называемого дополнением. Затем дополненное сообщение шифруется с использованием открытого ключа получателя.
  3. Передача зашифрованного текста. Зашифрованное сообщение передается или хранится в безопасном месте.

Расшифровка RSA:

  1. Расшифровка с закрытым ключом. Получатель использует свой закрытый ключ для расшифровки зашифрованного текста, который преобразуется обратно в дополненное сообщение.
  2. Удаление заполнения.Дополненное сообщение преобразуется обратно в исходное текстовое сообщение с использованием того же обратимого процесса заполнения, который используется при шифровании.

Сначала необходимо добавить в проект необходимый пакет NuGet System.Security.Cryptography.Algorithms, чтобы использовать шифрование RSA в проекте .NET. Для этого запустите Visual Studio и диспетчер пакетов NuGet или введите следующую команду в консоли диспетчера пакетов:

Install-Package System.Security.Cryptography.Algorithms

После установки пакета вы можете использовать класс RSA для выполнения шифрования и дешифрования. Вот пример использования шифрования RSA в .NET 6:

using System;
using System.Security.Cryptography;

class Program
{
    static void Main(string[] args)
    {
        byte[] dataToEncrypt = new byte[] { 1, 2, 3, 4, 5 };

        using RSA rsa = RSA.Create();
        byte[] encryptedData = rsa.Encrypt(dataToEncrypt, RSAEncryptionPadding.OaepSHA256);

        Console.WriteLine($"Encrypted Data: {Convert.ToBase64String(encryptedData)}");
    }
}

В приведенном выше коде мы сначала создаем экземпляр класса RSA, используя метод Create(). Затем мы предоставляем данные, которые хотим зашифровать, в массиве dataToEncrypt байт. Затем мы вызываем метод Encrypt() класса RSA для шифрования данных. Вторым параметром метода Encrypt() является значение RSAEncryptionPadding, указывающее схему заполнения, используемую при шифровании. В этом примере мы используем схему заполнения OaepSHA256, которая рекомендуется для большинства сценариев.

После шифрования мы преобразуем зашифрованные данные в строку Base64 с помощью метода Convert.ToBase64String() и отображаем их в консоли.

Шифрование RSA — это мощный инструмент для защиты конфиденциальных данных в вашем проекте .NET. Используя этот алгоритм шифрования, вы можете гарантировать, что ваши данные защищены и защищены от несанкционированного доступа.

реальный сценарий

Вот пример использования шифрования RSA в реальном сценарии.

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

Во-первых, вы должны сгенерировать пару открытого и закрытого ключей, используя класс RSACryptoServiceProvider, который является частью пространства имен System.Security.Cryptography. Затем вы должны безопасно хранить закрытый ключ на своем сервере и распространять открытый ключ среди всех клиентов, которым необходимо шифровать данные.

Вот пример того, как сгенерировать пару ключей и зашифровать строку с помощью шифрования RSA:

using System;
using System.Security.Cryptography;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        string dataToEncrypt = "Sensitive information";

        // Generate key pair
        using RSA rsa = RSA.Create();
        string publicKey = Convert.ToBase64String(rsa.ExportSubjectPublicKeyInfo());
        string privateKey = Convert.ToBase64String(rsa.ExportRSAPrivateKey());

        // Encrypt data
        byte[] dataBytes = Encoding.UTF8.GetBytes(dataToEncrypt);
        byte[] encryptedData = rsa.Encrypt(dataBytes, RSAEncryptionPadding.OaepSHA256);
        string encryptedDataString = Convert.ToBase64String(encryptedData);

        Console.WriteLine($"Public key: {publicKey}");
        Console.WriteLine($"Encrypted data: {encryptedDataString}");
    }
}

В приведенном выше коде мы сначала генерируем новую пару ключей RSA, используя метод Create() класса RSA. Затем мы преобразуем открытый ключ и закрытый ключ в строки Base64, которые можно легко передать клиентам и безопасно хранить на сервере соответственно.

Затем мы преобразуем строковые данные в массив байтов, используя кодировку UTF-8, а затем шифруем данные, используя метод Encrypt() класса RSA со схемой заполнения OaepSHA256. Наконец, мы конвертируем зашифрованные данные в строку Base64 для удобства хранения и передачи.

Чтобы расшифровать данные, вы должны получить закрытый ключ из безопасного хранилища и использовать его для расшифровки данных с помощью метода Decrypt() класса RSA. Вот пример расшифровки данных:

// Decrypt data
byte[] encryptedDataBytes = Convert.FromBase64String(encryptedDataString);
byte[] decryptedDataBytes = rsa.Decrypt(encryptedDataBytes, RSAEncryptionPadding.OaepSHA256);
string decryptedData = Encoding.UTF8.GetString(decryptedDataBytes);

Console.WriteLine($"Decrypted data: {decryptedData}");

В приведенном выше коде мы сначала преобразуем зашифрованную строку данных обратно в массив байтов, а затем используем метод Decrypt() класса RSA для расшифровки данных с помощью закрытого ключа. Наконец, мы преобразуем расшифрованный массив байтов обратно в строку, используя кодировку UTF-8.

Используя шифрование RSA, вы можете гарантировать, что конфиденциальные данные защищены от несанкционированного доступа и что только авторизованные пользователи с закрытым ключом могут расшифровать данные.

3.2 ECC (криптография на основе эллиптических кривых)

Популярным и современным алгоритмом шифрования с открытым ключом, известным своей высокой безопасностью и эффективностью, является криптография на эллиптических кривых (ECC). Пары открытого и закрытого ключей, созданные ECC, могут использоваться для шифрования и дешифрования. Эти пары ключей создаются с использованием эллиптических кривых над конечными полями. Здесь мы рассмотрим, как использовать ECC в вашем проекте .NET, и приведем пример кода.

Как это работает?

ECC-шифрование:

  1. Генерация ключей. Пара открытого и закрытого ключей генерируется с использованием математического алгоритма, основанного на эллиптических кривых. Открытый ключ предоставляется всем, кто хочет отправлять зашифрованные сообщения, а закрытый ключ хранится в секрете.
  2. Шифрование открытого текста. Сообщение открытого текста преобразуется в числовое значение с помощью обратимого процесса, называемого дополнением. Затем дополненное сообщение шифруется с использованием открытого ключа получателя.
  3. Передача зашифрованного текста. Зашифрованное сообщение передается или хранится в безопасном месте.

Расшифровка ЕСС:

  1. Расшифровка с закрытым ключом: получатель использует свой закрытый ключ для расшифровки зашифрованного текста, который преобразуется обратно в дополненное сообщение.
  2. Pдобавление удаления:дополненное сообщение преобразуется обратно в исходное текстовое сообщение с использованием того же обратимого процесса заполнения, который используется при шифровании.

Прежде чем использовать ECC в проекте .NET, убедитесь, что в вашем проекте есть соответствующий пакет NuGet System.Security.Cryptography.Algorithms. Это можно сделать, запустив диспетчер пакетов NuGet Visual Studio или введя следующую команду в консоли управления пакетами:

Install-Package System.Security.Cryptography.Algorithms

После установки пакета вы можете использовать класс ECDsa для выполнения шифрования и дешифрования с помощью ECC. Вот пример использования шифрования ECC в .NET 6:

using System;
using System.Security.Cryptography;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        string dataToEncrypt = "Sensitive information";

        // Generate key pair
        using ECDsa ecdsa = ECDsa.Create();
        string publicKey = Convert.ToBase64String(ecdsa.ExportSubjectPublicKeyInfo());
        string privateKey = Convert.ToBase64String(ecdsa.ExportPkcs8PrivateKey());

        // Encrypt data
        byte[] dataBytes = Encoding.UTF8.GetBytes(dataToEncrypt);
        byte[] encryptedData = ecdsa.SignData(dataBytes, HashAlgorithmName.SHA256);
        string encryptedDataString = Convert.ToBase64String(encryptedData);

        Console.WriteLine($"Public key: {publicKey}");
        Console.WriteLine($"Encrypted data: {encryptedDataString}");
    }
}

В приведенном выше коде мы сначала генерируем новую пару ключей ECC, используя метод Create() класса ECDsa. Затем мы преобразуем открытый ключ и закрытый ключ в строки Base64, которые можно легко передать клиентам и безопасно хранить на сервере соответственно.

Затем мы преобразуем строковые данные в массив байтов с использованием кодировки UTF-8, а затем шифруем данные с помощью метода SignData() класса ECDsa с алгоритмом хеширования SHA-256. Наконец, мы конвертируем зашифрованные данные в строку Base64 для удобства хранения и передачи.

Чтобы расшифровать данные, вы должны получить открытый ключ от клиента и использовать его для проверки подписи с помощью метода VerifyData() класса ECDsa. Вот пример расшифровки данных:

// Decrypt data
byte[] encryptedDataBytes = Convert.FromBase64String(encryptedDataString);
bool isVerified = ecdsa.VerifyData(dataBytes, encryptedDataBytes, HashAlgorithmName.SHA256);
string decryptedData = Encoding.UTF8.GetString(dataBytes);

Console.WriteLine($"Decrypted data: {decryptedData}");

В приведенном выше коде мы сначала преобразуем зашифрованную строку данных обратно в массив байтов, а затем используем метод VerifyData() класса ECDsa для проверки подписи с помощью открытого ключа. Наконец, мы преобразуем расшифрованный массив байтов обратно в строку, используя кодировку UTF-8.

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

Заключение

В заключение, методы шифрования имеют решающее значение для защиты конфиденциальных данных и безопасности аутентификации. Симметричные и асимметричные методы шифрования являются двумя основными категориями.

Методы симметричного шифрования используют один и тот же ключ как для шифрования, так и для дешифрования, что может подорвать безопасность, если ключ будет скомпрометирован. Тем не менее, они быстрые и эффективные. Хотя методы асимметричного шифрования медленнее и менее эффективны, они обеспечивают более высокий уровень защиты.

Подводя итог плюсам и минусам симметричных и асимметричных алгоритмов шифрования:

Алгоритмы симметричного шифрования:

Плюсы:

  • Быстро и эффективно.
  • Подходит для шифрования больших объемов данных.

Минусы:

  • Использует один и тот же ключ для шифрования и дешифрования, что может поставить под угрозу безопасность, если ключ будет скомпрометирован.
  • Не подходит для сценариев, где требуется более высокий уровень безопасности.

Алгоритмы асимметричного шифрования:

Плюсы:

  • Обеспечивает более высокий уровень безопасности, чем симметричное шифрование.
  • Использует два ключа, открытый ключ для шифрования и закрытый ключ для расшифровки, что гарантирует, что даже если открытый ключ известен, данные не могут быть расшифрованы без закрытого ключа.

Минусы:

  • Медленнее и менее эффективно, чем симметричное шифрование.
  • Не подходит для шифрования больших объемов данных.

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

Понимание преимуществ и недостатков алгоритмов симметричного и асимметричного шифрования может помочь вам выбрать правильный метод для вашего приложения и гарантировать защиту ваших данных от нежелательного доступа.

→ → → → → → → → → → → → → → → → → → → → → → → → →



Повышение уровня кодирования

Спасибо, что являетесь частью нашего сообщества! Перед тем, как ты уйдешь:

  • 👏 Хлопайте за историю и подписывайтесь на автора 👉
  • 📰 Смотрите больше контента в публикации Level Up Coding
  • 💰 Бесплатный курс собеседования по программированию ⇒ Просмотреть курс
  • 🔔 Подписывайтесь на нас: Twitter | ЛинкедИн | "Новостная рассылка"

🚀👉 Присоединяйтесь к коллективу талантов Level Up и найдите прекрасную работу