1

スケジュール要素などで複数のグループを管理し、子供たちの医療情報も管理するシンプルなシステムを求めている非営利団体に無料相談を行っています。そのすべてがExcelファイルにありますが、問題は看護師にとってあまり便利ではありません。だから私はこのasp.netアプリケーションを構築していて、機密データの暗号化に関して壁にぶつかりました。私はこのウェブサイトの本と推奨事項に続いてこのc#コードを書きました。私はそれを正しくやっていますか?

 using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Web.UI.WebControls;

public partial class SymmetricEncryptionWithPassword : System.Web.UI.Page
{

    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void Encrypt_OnClick(object sender, EventArgs e)
    {
        // Initialize the algorithm from the values on the page.
        SymmetricAlgorithm symmetricAlgorithm = new AesManaged();

        byte[] generatedKey = null;
        byte[] generatedIV = null;

        TextBox salt = (TextBox)DetailsView1.FindControl("TextBox2");
        TextBox ssn = (TextBox)DetailsView1.FindControl("TextBox1");

        salt.Text = Convert.ToBase64String(GenerateSalt());

        GetKeyAndIVFromPasswordAndSalt(this.password.Text, Convert.FromBase64String(salt.Text), symmetricAlgorithm, ref generatedKey, ref generatedIV);

        symmetricAlgorithm.Key = generatedKey;
        symmetricAlgorithm.IV = generatedIV;

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

        // Create the streams used for encryption.
        MemoryStream memoryStream = new MemoryStream();
        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
        {
            byte[] plainTextAsBytes = new UTF8Encoding(false).GetBytes(ssn.Text);
            cryptoStream.Write(plainTextAsBytes, 0, plainTextAsBytes.Length);
        }

        symmetricAlgorithm.Clear();

        byte[] encryptedData = memoryStream.ToArray();
        ssn.Text = Convert.ToBase64String(encryptedData);


    }


    protected void Decrypt_OnClick(object sender, EventArgs e)
    {
        // Initialize the algorithm from the values on the page.
        SymmetricAlgorithm symmetricAlgorithm = new AesManaged();

        byte[] generatedKey = null;
        byte[] generatedIV = null;

        TextBox txt = (TextBox)DetailsView1.FindControl("TextBox2");
        TextBox txt1 = (TextBox)DetailsView1.FindControl("TextBox1");
        GetKeyAndIVFromPasswordAndSalt(this.password.Text, Convert.FromBase64String(txt.Text), symmetricAlgorithm, ref generatedKey, ref generatedIV);

        symmetricAlgorithm.Key = generatedKey;
        symmetricAlgorithm.IV = generatedIV;

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

        // Create the streams used for encryption.
        MemoryStream memoryStream = new MemoryStream();
        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
        {
            byte[] encryptedDataAsBytes = Convert.FromBase64String(txt1.Text);
            cryptoStream.Write(encryptedDataAsBytes, 0, encryptedDataAsBytes.Length);
        }

        symmetricAlgorithm.Clear();

        byte[] decryptedData = memoryStream.ToArray();

        txt1.Text = Encoding.UTF8.GetString(decryptedData);

               }


    private static byte[] GenerateSalt()
    {
        const int MinSaltSize = 8;
        const int MaxSaltSize = 16;

        // Generate a random number to determine the salt size.
        Random random = new Random();
        int saltSize = random.Next(MinSaltSize, MaxSaltSize);

        // Allocate a byte array, to hold the salt.
        byte[] saltBytes = new byte[saltSize];

        // Initialize the cryptographically secure random number generator.
        RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

        // Fill the salt with cryptographically strong byte values.
        rng.GetNonZeroBytes(saltBytes);

        return saltBytes;
    }


    private static void GetKeyAndIVFromPasswordAndSalt(string password, byte[] salt, SymmetricAlgorithm symmetricAlgorithm, ref byte[] key, ref byte[] iv)
    {
        Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt);
        key = rfc2898DeriveBytes.GetBytes(symmetricAlgorithm.KeySize / 8);
        iv = rfc2898DeriveBytes.GetBytes(symmetricAlgorithm.BlockSize / 8);
    }
}
}

コードは機能します。データを入力すると、データベースに暗号化され、適切なSaltが値とともに保存されます。たとえば、テキストボックスで復号化する場合は、正しく機能します。

私の考えは次のとおりです。看護師はフォームにデータを入力し、パスワードで暗号化します。暗号化されたMediCare番号とソルト値がサーバーによって生成され、SQLサーバーに送信されます。MediCareは次のようなテーブルで暗号化されます。 。

Medicare_ID-int(主キー)
Medicar_Number-(varchar(MAX))
Medicare_SALT-(varchar(MAX))

復号化パスワードはデータベースに保存されていません。私はこれを目的で行いました。

ここでのベストプラクティスに従っているかどうかはわかりませんが、物理サーバーが盗まれた場合に情報を簡単に復号化できますか?彼らはまだデータを復号化するためのパスワードの権利を必要としていますか?緊急時に復号化する必要がある場合があります。私の復号化方法は安全ですか?もう1つの懸念は、1and1共有ウェブホスティングを使用していることです。

情報が暗号化されて目が落ちるのを防ぐために、SSLがWebサイトでアクティブ化されるなど、さらにいくつかのセキュリティ対策を設定しました。

万が一に備えて、接続文字列と入力がサニタイズされるようにしますが、理論的には、1〜2人のマネージャーまたは看護師だけがデータを操作します。

Webサイトへのアクセスは、VisualStudio2010から借用したログインコントロールを使用したユーザー名パスワードで保護されています。

これを読んでくれてありがとう

4

5 に答える 5

1

主な質問に答えるには:

ここでのベスト プラクティスに従っているかどうかわかりませんが、物理サーバーが盗まれた場合、私の情報は簡単に解読できますか?

盗まれたサーバーについて: 何をしても、乗っ取られます。盗まれたハードウェアに対して完璧な既知のセキュリティはありません。ラップトップの暗号化されたハード ドライブでさえ、暗号化を提供する企業が信じているよりも速い時間で壊れることがあります。ハードウェアを物理的に手に入れるという道をたどった場合、彼らは次の 2 つのいずれかを実行します: それを消去して部品を転売するか、データをクラックします。道徳的に (場合によっては法的に)、最終的に何が起こるかに関係なく、データが盗まれたことをすべてのクライアントに通知する必要があります。

要点は次のとおりだと思います。暗号化は、悪者がデータを盗むことができないという意味ではありません。それは単に時間がかかることを意味します。時間を稼ぐために物事を暗号化します。ロックを変更する時間、クライアントに通知する時間、パスワードを変更する時間。そして、SSN やその他の貴重なデータを扱うときは、クレジット アカウントにロックをかける時間です。

データを復号化するには、パスワードの権利が必要ですか?

必ずしも。パスワードをどこかに保存しなければならないことを気にしないでください。彼らがあなたの DB サーバーを盗んだ場合、Web サーバー (資格情報を持つ) も持ち去った可能性があります。

緊急の場合に備えて、暗号化を解除する必要がある場合があります。

「緊急」の復号化について: これを処理するには 2 つの方法があります。そのパスワードのコピーを入手できる場所に保存するか、解読してください。

私の復号化方法は安全ですか?

あなたの方法は時間の無駄だと思います。詳細については、以下を参照してください。


この時点で、マシンへの物理的なアクセスは、そのデータへの完全なアクセスと同等であることを理解する必要があります。したがって、武装した警備員がいる本当に安全な場所に保管しているという考えがなければ、できることはあまりありません. 通常、典型的なデータセンターのセキュリティ (Amazon クラウドなど) で十分です。ただし、政府データの場合、一部の企業 (Amazon など) は、追加のセキュリティが必要と思われるデータを保持するためだけに専用のサーバーを用意しています。1 と 1 のホスティングがこれを行うとは思えません。

それでは、より良いオプションが何であるかを見てみましょう。varchar(max) に言及しているため、MS SQL Server を使用していると仮定します。SQL Server には、データベースの暗号化が組み込まれています。これをオンにします。誰かが DB ファイル (サーバーではなくファイルのみ) のコピーを取得した場合、SQL の暗号化を解読してデータにアクセスする必要があります。これを上回るためにできることは何もなく、鍵の管理についてあまり心配する必要はありません。これにより、「保存中のデータ」が処理されます。確かにもう一度暗号化することはできますが、MS SQL Server に組み込まれているセキュリティについて調べたほうが、時間を有効に活用できると思います。

「移動中のデータ」の場合、Web サーバーとデータベース サーバー間の通信用に kerberos をオンにする必要があります。(つまり、誰かが Web サーバーと db サーバーの間の接続をリッスンしようとしていないことを信頼しないでください。また、ルーターが適切に構成されていることを信頼しないでください。構成されていることはめったにありません。) 適切な方法を読んでください。 AD 環境を構成します。また、Web サーバーとクライアント デスクトップ間の通信用に SSL をオンにする必要があります。

暗号化を超えて、2 つの重要な点に注意する必要があります。1 つ目は、Web サイトがデータベースに対して持っているアクセスのレベルです。そのユーザー アカウントは基本的に SA レベルの権限を持っていますか? もしそうなら、あなたはそれを間違っています。サイトが使用するアカウントは、絶対に必要なアイテムの実行のみに限定する必要があります。つまり、誰かがテーブルを削除または変更したり、アクセスしてはならないデータを完全に選択したりすることを許可してはなりません。これは、Web アプリケーションの大部分が失敗する場所です。プログラマーは、データベースに直接アクセスできるのは Web アプリだけだと考えています。現実には、ページなどを既存のアプリに挿入するのは簡単すぎる場合があります。補足として、これはほとんどの ORM、EF、および L2S を備えた私の主なビーフです。彼らはあまりにも多くのアクセスを必要とします。

Web 構成で接続文字列を暗号化するとよく言いますが、それは一般的に時間の無駄です。結局のところ、web.config を読み取ることができれば、暗号化されていないコンテンツをアプリに吐き出させるのに十分なアクセス権を持っている可能性があります。これにより、Web サイトがデータベースに対して持っているアクセス レベルに戻ります。無罪が証明されない限り、誰もが有罪であるという確固たる信念が最善の策です。

何らかの理由で、Web サーバーとデータベース サーバーが同じ物理ボックス上にある場合: これを変更します。それは悪い考えです.Webサイトがクラックされると、(ほとんどのサイトがどのように構築されているかにより) dbサーバーへのsaレベルのアクセスを取得することは簡単になります.

次に、ロギングをオンにします。DB では、少なくともログインの失敗と成功の両方をログに記録する必要があります。Web サイトで、すべてをログに記録します。また、外部から db サーバーへの直接アクセスをオフにします。その間に、通信に非標準ポート (つまり、1433/2433 ではない) を使用するように db サーバーを切り替えます。DB サーバーのファイアウォールが、その Web サーバーからの接続のみを許可するように適切に構成されていることを確認してください。

細かい櫛でコードを調べます。OWASPを読んでください。入力をサニタイズします。それらすべて。すべての DB クエリがパラメーターを渡し、動的に何も構築していないことを確認してください。SA アカウントを無効にします。

これは少し長くなりました。しかし、それが教育的だったことを願っています。

于 2012-04-24T23:24:50.273 に答える
0
  • 共有ホスティング: 政府の要件を確認してください。私は医療分野に携わっているわけではありませんが、機密性の高い個人情報の保管を管理する規則や法律がない場合は非常に驚きます。クレジット カード/e コマースに PCI DSS 要件がある場合、医療データには少なくとも同じレベルの (おそらくより厳しい) データ保護規則 ( HIPAAなど) があると思います。

  • 1&1 についてはよくわかりませんが、「どこ」も問題になる可能性があります (?) - (1&1 の) サーバーは物理的にどこにありますか?

  • さらに別の考え: ユーザーがソルト/パスワードを生成する代わりに (それらはどのくらいの期間/安全である必要がありますか?)、おそらくSQL サーバーの暗号化オプションを調べて、ジョブをユーザーやコードではなく SQL に移動します。

  • データを暗号化またはハッシュ化する必要があるかどうかを決定します (ストレージ/取得とルックアップ) - re: password = hashed, SSN - 私が推測する使用法に依存します。ハッシュはSQL Serverでも行うことができます....

于 2012-04-24T06:33:36.090 に答える
0

正確な答えはわかりませんが、システムを保護する方法についていくつかの考えを共有できます. 現在の既存の暗号化は、将来クラックされるでしょう。それは問題ではありませんが、いつです。そうは言っても、次のことを自問することをお勧めします。

  • どのくらいの期間データを安全に保ちたいですか? 10 年以内の情報を保存する場合は、AES-128 で十分です。ただし、20 年以上保存する場合は、少なくとも AES-256 の使用を検討してください。

  • 悪者がコードを解読した場合、彼らは何を得ますか? 暗号化に加えて、暗号化された文字列/情報を 2 つ以上の場所に保存するなど、「あいまいさによるセキュリティ」を使用して南京錠を追加することもできます。

  • 内部からの確保。ユーザーはどの程度セキュリティを認識していますか? パスワードをキーボードの下に保存したり、ログイン情報を共有したり、画面がロックされていないときに立ち去ったりしますか。それらのいずれかが「はい」の場合は、UI デザインについて考える必要があるかもしれません。チェーンは、その最も弱いリンクと同じくらい強力です。

于 2012-04-24T05:36:56.763 に答える
0

この関数は悪い習慣です。安全を確保するために IV はランダムである必要があります。同じ IV を同じキーに使用することはできません。これにより、特定のキーに対して常に同じ IV が与えられ、安全ではなくなります。

private static void GetKeyAndIVFromPasswordAndSalt(string password, byte[] salt, SymmetricAlgorithm symmetricAlgorithm, ref byte[] key, ref byte[] iv)
{
    Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt);
    key = rfc2898DeriveBytes.GetBytes(symmetricAlgorithm.KeySize / 8);
    iv = rfc2898DeriveBytes.GetBytes(symmetricAlgorithm.BlockSize / 8);
}
于 2012-04-24T21:32:48.870 に答える
0

これは、RijndaelManaged CryptoServiceProvider を使用して機密情報を暗号化および復号化する方法の良い例です。

Rijndaelマネージド暗号化

于 2012-04-24T01:59:32.267 に答える