Как надежно сохранить логин / пароль (локальный)?

Я делаю приложение для Windows, в которое вы должны войти в первую очередь.
Данные учетной записи состоят из имени пользователя и пароля, и они должны быть сохранены локально.
Это просто вопрос безопасности, поэтому другие люди, использующие один и тот же компьютер, не могут видеть личные данные каждого.
Какой самый лучший / самый безопасный способ сохранить эти данные?

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

6 ответов

Решение

Если вы просто собираетесь проверить / проверить введенные имя пользователя и пароль, используйте класс Rfc2898DerivedBytes (также известный как Функция получения ключа на основе пароля 2 или PBKDF2). Это более безопасно, чем использование шифрования, такого как Triple DES или AES, потому что нет практического способа перейти от результата RFC2898DerivedBytes к паролю. Вы можете перейти только от пароля к результату. См. Можно ли использовать хеш-пароль SHA1 в качестве соли при получении ключа шифрования и IV из строки пароля? для примера и обсуждения для.Net или String шифровать / дешифровать паролем C# Metro Style для WinRT/Metro.

Если вы храните пароль для повторного использования, например, для передачи его третьему лицу, используйте API защиты данных Windows (DPAPI). При этом используются сгенерированные и защищенные ключи операционной системы и алгоритм шифрования Triple DES для шифрования и дешифрования информации. Это означает, что вашему приложению не нужно беспокоиться о создании и защите ключей шифрования, что является серьезной проблемой при использовании криптографии.

В C# используйте класс System.Security.Cryptography.ProtectedData. Например, чтобы зашифровать часть данных, используйтеProtectedData.Protect():

// Data to protect. Convert a string to a byte[] using Encoding.UTF8.GetBytes().
byte[] plaintext; 

// Generate additional entropy (will be used as the Initialization vector)
byte[] entropy = new byte[20];
using(RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
    rng.GetBytes(entropy);
}

byte[] ciphertext = ProtectedData.Protect(plaintext, entropy,
    DataProtectionScope.CurrentUser);

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

byte[] plaintext= ProtectedData.Unprotect(ciphertext, entropy,
    DataProtectionScope.CurrentUser);

Обратите внимание, что существуют дополнительные соображения безопасности. Например, избегайте хранения таких секретов, как пароли, как string, Строки являются неизменяемыми, поскольку они не могут быть уведомлены в памяти, так что кто-то, просматривающий память приложения или дамп памяти, может увидеть пароль. Вместо этого используйте SecureString или byte[] и не забудьте утилизировать или обнулить их, как только пароль больше не нужен.

Я хотел зашифровать и расшифровать строку как читаемую строку.

Вот очень простой быстрый пример в C# Visual Studio 2019 WinForms на основе ответа от @Pradip.

Щелкните правой кнопкой мыши проект> свойства> настройки> создать username а также password настройка.

Теперь вы можете использовать только что созданные настройки. Здесь я сохраняюusername а также password но только зашифровать password в поле респектабельного значения в user.config файл.

Пример зашифрованной строки в user.config файл.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <userSettings>
        <secure_password_store.Properties.Settings>
            <setting name="username" serializeAs="String">
                <value>admin</value>
            </setting>
            <setting name="password" serializeAs="String">
                <value>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAQpgaPYIUq064U3o6xXkQOQAAAAACAAAAAAAQZgAAAAEAACAAAABlQQ8OcONYBr9qUhH7NeKF8bZB6uCJa5uKhk97NdH93AAAAAAOgAAAAAIAACAAAAC7yQicDYV5DiNp0fHXVEDZ7IhOXOrsRUbcY0ziYYTlKSAAAACVDQ+ICHWooDDaUywJeUOV9sRg5c8q6/vizdq8WtPVbkAAAADciZskoSw3g6N9EpX/8FOv+FeExZFxsm03i8vYdDHUVmJvX33K03rqiYF2qzpYCaldQnRxFH9wH2ZEHeSRPeiG</value>
            </setting>
        </secure_password_store.Properties.Settings>
    </userSettings>
</configuration>

Полный код

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace secure_password_store
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Exit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void Login_Click(object sender, EventArgs e)
        {
            if (checkBox1.Checked == true)
            {
                Properties.Settings.Default.username = textBox1.Text;
                Properties.Settings.Default.password = EncryptString(ToSecureString(textBox2.Text));
                Properties.Settings.Default.Save();
            }
            else if (checkBox1.Checked == false)
            {
                Properties.Settings.Default.username = "";
                Properties.Settings.Default.password = "";
                Properties.Settings.Default.Save();
            }
            MessageBox.Show("{\"data\": \"some data\"}","Login Message Alert",MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        private void DecryptString_Click(object sender, EventArgs e)
        {
            SecureString password = DecryptString(Properties.Settings.Default.password);
            string readable = ToInsecureString(password);
            textBox4.AppendText(readable + Environment.NewLine);
        }
        private void Form_Load(object sender, EventArgs e)
        {
            //textBox1.Text = "UserName";
            //textBox2.Text = "Password";
            if (Properties.Settings.Default.username != string.Empty)
            {
                textBox1.Text = Properties.Settings.Default.username;
                checkBox1.Checked = true;
                SecureString password = DecryptString(Properties.Settings.Default.password);
                string readable = ToInsecureString(password);
                textBox2.Text = readable;
            }
            groupBox1.Select();
        }


        static byte[] entropy = Encoding.Unicode.GetBytes("SaLtY bOy 6970 ePiC");

        public static string EncryptString(SecureString input)
        {
            byte[] encryptedData = ProtectedData.Protect(Encoding.Unicode.GetBytes(ToInsecureString(input)),entropy,DataProtectionScope.CurrentUser);
            return Convert.ToBase64String(encryptedData);
        }

        public static SecureString DecryptString(string encryptedData)
        {
            try
            {
                byte[] decryptedData = ProtectedData.Unprotect(Convert.FromBase64String(encryptedData),entropy,DataProtectionScope.CurrentUser);
                return ToSecureString(Encoding.Unicode.GetString(decryptedData));
            }
            catch
            {
                return new SecureString();
            }
        }

        public static SecureString ToSecureString(string input)
        {
            SecureString secure = new SecureString();
            foreach (char c in input)
            {
                secure.AppendChar(c);
            }
            secure.MakeReadOnly();
            return secure;
        }

        public static string ToInsecureString(SecureString input)
        {
            string returnValue = string.Empty;
            IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input);
            try
            {
                returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
            }
            finally
            {
                System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
            }
            return returnValue;
        }

        private void EncryptString_Click(object sender, EventArgs e)
        {
            Properties.Settings.Default.password = EncryptString(ToSecureString(textBox2.Text));
            textBox3.AppendText(Properties.Settings.Default.password.ToString() + Environment.NewLine);
        }
    }
}

Я использовал это раньше, и я думаю, чтобы убедиться, что учетные данные сохраняются и самым безопасным способом

  1. Вы можете записать их в файл конфигурации приложения, используя ConfigurationManager учебный класс
  2. защита пароля с помощью SecureString учебный класс
  3. затем шифровать его с помощью инструментов в Cryptography Пространство имен.

Надеюсь, эта ссылка очень поможет: нажмите здесь

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

Это работает только в Windows, поэтому, если вы планируете использовать кроссплатформенное ядро ​​dotnet, вам придется искать в другом месте. См. https://github.com/dotnet/corefx/blob/master/Documentation/architecture/cross-platform-cryptography.md

Для простых сценариев также можно использовать Windows Credential Management API с помощью оболочки C# CredentialManagement . Это дает единое место для хранения / извлечения паролей, которые легко изменить.

/questions/29609830/kak-hranit-i-poluchat-uchetnyie-dannyie-na-oknah-ispolzuya-c/29609839#29609839

Другие вопросы по тегам