2013-02-12 176 views
1

我在SSIS 2008 C#腳本組件(.NET 3.5)中使用的OAuthBase類找到了HEREC#中OAuth隨機數的線程安全隨機數/字符串生成器

它一直工作正常,但最近我遇到了問題,如果我在同一個數據流任務中使用上述OAuthBase類中的GenerateNonce方法執行多個腳本組件,我最終會得到相同的nonce(隨機數)。

下面是來自OAuthBase類的摘錄生成隨機數:

using System; 
using System.Security.Cryptography; 
using System.Collections.Generic; 
using System.Text; 
using System.Web; 

namespace OAuth { 
public class OAuthBase { 

    ....snip...... 

    protected Random random = new Random(); 

    public virtual string GenerateNonce() { 
     // Just a simple implementation of a random number between 123400 and 9999999 
     return random.Next(123400, 9999999).ToString(); 
    } 
    } 
} 

在每個腳本組件我使用這個C#代碼來啓動類,並生成一個隨機數:

 OAuthBase oAuth = new OAuthBase(); 
     string nonce = oAuth.GenerateNonce(); 

從我的搜索中我認爲這與它不是線程安全有關?我不完全確定。

我只能在SSIS 2008中運行.NET 3.5,所以我知道一些在.NET 4.0中引入的新東西,我無法使用。

有關如何修改OAuthBase類和/或C#腳本組件代碼的任何想法?

+0

此隨機數的可能值很少。除了線程缺陷之外,它不是唯一的。 – usr 2013-02-12 23:33:14

+0

@usr - 謝謝。那時候我想過那個。也許我只是做一些像'return Guid.NewGuid.ToString();'?我不完全確定我的隨機數可以達到多長時間(擊中Magento REST API)。 – jared 2013-02-12 23:41:16

回答

5

如果您同時創建多個OAuthBase實例,則單個實例完全有可能具有相同種子的Random實例,默認情況下種子是當前滴答計數。所以這意味着Random的個體實例可能已經用相同的種子創建。嘗試使Random實例靜態。但由於Random is not thread safe。您需要保護對其的訪問。

private static readonly Random random = new Random(); 
private static readonly object randLock = new object(); 

public virtual string GenerateNonce() 
{ 
    lock (randLock) 
    { 
     // Just a simple implementation of a random number between 123400 and 9999999 
     return random.Next(123400, 9999999).ToString(); 
    } 
} 

// since you had protected access on random, I'm assuming sub classes want to use it 
// so you'll need to provide them with access to it 
protected int NextRandom(...) 
{ 
    lock (randLock) 
    { 
     random.Next(...); 
    } 
} 

但正如其他人所說,因爲你沒有一個保密性強的隨機源,你可能想看看其他的方法來生成你的價值。

// RNGCryptoServiceProvider is thread safe in .NET 3.5 and above 
// .NET 3.0 and below will need locking to protect access 
private static readonly RNGCryptoServiceProvider random = 
    new RNGCryptoServiceProvider(); 

public /*virtual*/ byte[] GenerateNonce(int length) 
{ 
    // a default length could be specified instead of being parameterized 
    var data = new byte[length]; 
    random.GetNonZeroBytes(data); 
    return data; 
} 
// or 
public /*virtual*/ string GenerateNonce(int length) 
{ 
    var data = new byte[length]; 
    random.GetNonZeroBytes(data);   
    return Convert.ToBase64String(data); 
} 
+0

與[RNGCryptoServiceProvider](http://msdn.microsoft.com/zh-cn/library/system.security.cryptography.rngcryptoserviceprovider.aspx)一樣,將[Random]替換爲[usr said](http://stackoverflow.com/a/14843988/80274),你將有完美的答案。 – 2013-02-12 23:54:12

+0

@ScottChamberlain更新爲包含一個使用RNGCryptoServiceProvider的示例 – 2013-02-13 00:00:32

+2

只是在其他人不知情的情況下,[RNGCryptoServiceProvider僅適用於.NET 3.5以上版本的線程安全](http://msdn.microsoft.com/ en-us/library/system.security.cryptography.rngcryptoserviceprovider%28v = vs.85%29.aspx#threadSafetyToggle),所以如果你的目標是3.0或更高,你仍然需要使用鎖。 – 2013-02-13 00:04:36