Is SecureString a write-only class? - c#

I recently discovered SecureString and it seems to fit a perfect application where I want to basically initialize a static secret string at the beginning of an application, and then make it read-only and use it throughout the life of the application(as a portion of a hash).
I'm having trouble understanding how to even make use of the SecureString class.. From what I can tell, you can set the SecureString, but there is no way to compare the value or retrieve the value in any way.
What is the purpose of this class if it's write-only?

No, it's not write-only: you can retrieve a regular .NET String from the SecureString by using the Marshal class:
IntPtr ptr = Marshal.SecureStringToBSTR(secureString);
string str = Marshal.PtrToStringBSTR(ptr);
Marshal.ZeroFreeBSTR(ptr);
return str;
Note that this allocates unmanaged memory, so you need to be sure to free it (with Marshal.ZeroFreeBSTR) to avoid leaks. And it should go without saying that once you've converted it to a .NET String, you lose the benefits of SecureString (the String will remain in memory until it's GC'ed, it may be paged to disk, etc.).
The purpose of the SecureString class is that you can use it in APIs where the privacy of user data (e.g., passwords or credit card numbers) should be protected (e.g., if your application crashes and a minidump is saved to disk). A handful of classes in the .NET Framework (e.g., PasswordBox.SecurePassword) take a SecureString object in order to avoid exposing this data.

Both ways here, a way to convert it to a securestring and from a securestring. Of course the whole point of storing it in a securestring is to prevent it from being in memory in the first place.
#region SecureString Manipulation
/// <summary>
/// Convert a Securestring to a regular string (not considered best practice, but make sure it's not in memory if you can help it)
/// </summary>
/// <param name="securePassword">Password stored in a secure string</param>
/// <returns>regular string of securestring password</returns>
public static string ConvertToUnsecureString(this System.Security.SecureString securePassword)
{
if (securePassword == null)
throw new ArgumentNullException("securePassword");
IntPtr unmanagedString = IntPtr.Zero;
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
return Marshal.PtrToStringUni(unmanagedString);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
}
}
/// <summary>
/// Pass a text password to this function to return a SecureString (doesn't store the password in memory)
/// </summary>
/// <param name="password">Text version of a password</param>
/// <returns>SecureString of a password (not readable by memory)</returns>
public static SecureString ConvertToSecureString(this string password)
{
if (password == null)
throw new ArgumentNullException("password");
var secure = new SecureString();
foreach (var c in password.ToCharArray())
secure.AppendChar(c);
return secure;
}
#endregion

Related

Really destroy a string in c#

I am writing an API which will accept a standard string for a username and password as a means of compatibility. I know standard strings are not ideal and my API already uses the SecureString class for this purpose and my summaries above methods warn the API user of this. However since the API may not be used in an environment where SecureString is possible, I have written a function to really destroy a string as soon as my SecureString Extention methods convert the standard string to SecureString.
public static void CrunchString(ref string str) {
int l = str.Length;
unsafe {
fixed (char* c = str) {
for (int i = 0; i < l; ++i) {
c[i] = (char)0x00;
}
}
}
str = null;
}
Is this the right way about it or is there a better solution? Are there any consequences that could be forseen by destroying the string in this nature in-place?
The aim here is to really destroy the un secured string early on and to thoroughly remove it from normal memory.

Dependency Injection ASP.NET : Unaware about the dependencies until Runtime

I am using ASP.NET Core and using DI to build Hashing functionality. Since I don't know the type of hashing used at this stage (we are storing it in persistent storage).
The ICrypto Contract
public interface ICrypto
{
string HashPassword(string plainPassword);
bool VerifyHashedPassword(string hashedPassword, string providedPassword);
}
I have several Implementations of ICrypto and they just wrap other libraries and provide the implementation of ICrypto Signatures. For example:
CryptoMD5
CryptoSHA1
CytpoOther
Now, in UserService I inject the ICyrpto to hash passwords for example:
Public class UserService
{
ICrypto _crypto;
public UserService(ICrypto crypto)
{
_crypto = crypto;
}
public bool Login (string username, string password)
{
//code omitted
var hash = _crypto.HashPassword(password);
}
}
Adding Dependencies to the Container in Startup class
//get encryption type stored in cache, db or somewhere
var cryptoType = //get param
if (cryptoType = "SHA1")
{
services.AddTransient<ICrypto, CryptoSHA1>();
}
else if (cryptoType = "MD5")
{
services.AddTransient<ICrypto, CryptoMD5>();
}
I am looking for a way to do this according to best practices and will reflect what Steves has mentioned.
In case the cryptoType value you get from the database is constant during the lifetime of the application (which means, if you want to change it, you're fine with restarting the application), this means that the cryptoType is a configuration value and you can simply wire your application as you described:
var cryptoType = //get param
if (cryptoType = "SHA1")
{
services.AddTransient<ICrypto, CryptoSHA1>();
}
else if (cryptoType = "MD5")
{
services.AddTransient<ICrypto, CryptoMD5>();
}
If however you need to swap implementations dynamically (which I find very unlikely in your specific case, but let's assume for the sake of argument), the solution is to implement a proxy and wrap the real implementations. Example:
public interface DatabaseCryptoSelectorProxy : ICrypto
{
private readonly CryptoSHA1 sha;
private readonly CryptoMD5 md5;
public DatabaseCryptoSelectorProxy(CryptoSHA1 sha, CryptoMD5 md5) {
this.sha = sha;
this.md5 = md5;
}
public string HashPassword(string plainPassword) =>
GetCrypto().HashPasswords(plainPassword);
public bool VerifyHashedPassword(string hashedPassword, string providedPassword) =>
GetCrypto().VerifyHashedPassword(hashedPassword, providedPassword);
private ICrypto GetCrypto() {
var cryptoType = // get param
if (cryptoType = "SHA1") return this.sha;
if (cryptoType = "MD5") return this.md5;
throw new InvalidOperationException("Unknown cryptotype: " + cryptotype);
}
}
This proxy has a few clear advantages:
It makes the consumers of ICrypto oblivious to the fact that some complex dispatching is happening based on some data from a database.
It prevents having to execute this query during object graph construction, since this would make this process unreliable and hard to verify.
Some notes though about your design around password hashing from a security perspective. I don't see any strong reason to switch from crypto methods the way you are doing, and especially not the switch to algorithms like MD5. Instead, I advise using PBKDF2 in the form of Rfc2898DeriveBytes. An example of how to do this can be shown here. By concatenating the number of hash iterations to the hashed password (for instance by simply doing + "|" + iterations), you can later on increase the number of used iterations by keeping up with the industry standard and it allows you to automatically rehash the user's password on login if his number if you detect the number of used iterations an old value.
Additionally, if you think that you ever need to move away from PBKDF2, you can prefix the hash with the used algorithm, this way you can again use a proxy that passes a hashed password on to the right implementation based on the algorithm-prefix. By storing the algorithm in the password hash in the database, you can migrate transparently without having to convert all existing passwords at once (which is impossible, because you can't decrypt a hashed password).

How To Make More Functional?

I'm a c# guy who has learned JavaScript recently and thinking of going down the f# path. I love the functional nature of JavaScript but have trouble bring it into my c# code. I look at the below block of code and it really feels ugly. For those that are naturally bent towards functional programming, what would be a better way to do this block in either c# (or even f#).
(or am I barking up the wrong tree looking to improve it)
/// <summary>
/// Get the current Tenant based on tenantNameOverride if present,
/// otherwise uses urlHost to figure it out
/// case independent
/// if urlHost and tenantNameOverride empty then
/// throws exception
/// if tenantNameOverride specified and not found
/// throw exception
/// if tenantNameOverride not specified and there
/// is no default tenant, then throw exception
/// </summary>
/// <param name="tenants"></param>
/// <param name="urlHost"></param>
/// <param name="tenantNameOverride"></param>
/// <returns></returns>
private static Tenant GetTenantBasedOnUrlHost(
List<Tenant> tenants, string urlHost=null,
string tenantNameOverride=null)
{
if (String.IsNullOrEmpty(urlHost) &&
String.IsNullOrEmpty(tenantNameOverride))
{
throw new ApplicationException(
"urlHost or tenantName must be specified");
}
Tenant tenant;
if (String.IsNullOrEmpty(tenantNameOverride))
{
tenant = tenants.
FirstOrDefault(a => a.DomainName.ToLower().Equals(urlHost)) ??
tenants.FirstOrDefault(a => a.Default);
if (tenant == null)
{
throw new ApplicationException
("tenantName must be specified, no default tenant found");
}
}
else
{
tenant = tenants.FirstOrDefault
(a => a.Name.ToLower() == tenantNameOverride.ToLower());
if (tenant == null)
{
throw new ApplicationException
("tenantNameOverride specified and not found");
}
}
return tenant;
}
/********************* update below *****************/
Per Jon Skeet's suggestion, I've made two methods. With the exception of the error check at the top for empty string violations which I'm not sure we can easily avoid in c#. Throwing an exception also feels a little odd on not found but for my purposes, these methods should always find a tenant and if not that is unexpected and an exception seems reasonable.
This does seem cleaner and sticks better to the design guideline of single responsibility. Maybe that is what I did not like about my solution and it had nothing to do with functional or non-functional.
/// <summary>
/// Return tenant based on URL (or return default tenant if exists)
/// </summary>
/// <param name="tenants"></param>
/// <param name="urlHost"></param>
/// <returns></returns>
private static Tenant GetTenantBasedOnUrl(
List<Tenant> tenants, string urlHost)
{
if (String.IsNullOrEmpty(urlHost))
{
throw new ApplicationException(
"urlHost must be specified");
}
var tenant = tenants.
FirstOrDefault(a => a.DomainName.ToLower().Equals(urlHost)) ??
tenants.FirstOrDefault(a => a.Default);
if (tenant == null)
{
throw new ApplicationException
("tenant not found based on URL, no default found");
}
return tenant;
}
/// <summary>
/// Get exact tenant name match and do not return default even
/// if exists.
/// </summary>
/// <param name="tenants"></param>
/// <param name="tenantNameOverride"></param>
/// <returns></returns>
private static Tenant GetTenantByName(List<Tenant> tenants,
string tenantNameOverride)
{
if (String.IsNullOrEmpty(tenantNameOverride))
{
throw new ApplicationException(
"tenantNameOverride or tenantName must be specified");
}
var tenant = tenants.FirstOrDefault
(a => a.Name.ToLower() == tenantNameOverride.ToLower());
if (tenant == null)
{
throw new ApplicationException
("No tenant Found (not checking for default)");
}
return tenant;
}
}
Here's how I would approach the problem in F#.
First, if I understand the requirements correctly, the caller of the function must supply either a domain name, or a tenant name to search for. In C#, such an exclusive rule is difficult to model, which leads to the rule that at least one must be specified, but if both are specified, one of the arguments take precedence.
While such a rule is difficult to define using C#'s type system, it's trivial to declare in F#, using a Discriminated Union:
type TenantCriterion =
| DomainName of Uri
| Name of string
This means that a criterion searching for a tenant can be either a DomainName or a Name, but never both.
In my definition of DomainName, I changed the type to System.Uri. When you're dealing with URLs, it's generally safer to use Uri values than string values.
Instead of converting string values to lower case, it's safer to compare them using StringComparison.OrdinalIgnoreCase, if that's what you want, since there are all sorts of subtle localization issues if you convert e.g. Turkish strings to lower case (that conversion is lossy).
Finally, I changed the query to return Tenant option instead of throwing exceptions. In Functional Programming, we prefer to avoid exceptions. If you want more detailed exception handling than option you can use the Either monad.
All that said, here's a possible implementation of the function to find a tenant:
let findTenant tenants = function
| DomainName u ->
let t = tenants |> List.tryFind (fun x -> x.DomainName = u)
match t with
| Some t -> Some t
| None -> tenants |> List.tryFind (fun x -> x.IsDefault)
| Name n ->
tenants
|> List.tryFind
(fun x -> n.Equals(x.Name, StringComparison.OrdinalIgnoreCase))
This function has the type Tenant list -> TenantCriterion -> Tenant option. If you want more lazy evaluation, you can replace List.tryFind with Seq.tryFind.

.NET Secure Memory Structures

I know the .NET library offers a way of storing a string in a protected/secure manner = SecureString.
My question is, if I would like to store a byte array, what would be the best, most secure container to hold this?
It is important to understand the vulnerability of the System.String type. It is impossible to make it completely secure, SecureString exists to minimize the risk of exposure. System.String is risky because:
Their content is visible elsewhere, without having to use a debugger. An attacker can look in the paging file (c:\pagefile.sys), it preserves the content of RAM pages that were swapped out to disk to make room for other programs that need RAM
System.String is immutable, you cannot scrub the content of a string after you used it
The garbage collected heap compacts the heap but does not reset the content of the memory that was freed-up. Which can leave a copy of the string data in memory, entirely out of reach from your program.
The clear risk here is that the string content can be visible long after the string was used, thus greatly increasing the odds that an attacker can see it. SecureString provides a workaround by storing the string in unmanaged memory, where it is not subject to the garbage collector leaving stray copies of the string content.
It should be clear now how you can create your own version of secure array with the same kind of guarantees that SecureString provides. You do not have the immutability problem, scrubbing the array after you use it is not a problem. Which in itself is almost always good enough, implicit in reducing the likelihood of exposure is that you don't keep a reference to the array for very long either. So the odds of the non-scrubbed copy of the array data surviving after a garbage collection should already be low. You can reduce that risk as well, present only for arrays less than 85,000 bytes. Either by doing it the way SecureString does it and using Marshal.AllocHGlobal(). Or much easier by pinning the array, GCHandle.Alloc().
as of .Net 2.0 use the ProtectedData.Protect Method, looks like setting the scope to DataProtectionScope.CurrentUser should give the same desired effect as secure string
example usage taken from here
http://msdn.microsoft.com/en-us/library/system.security.cryptography.protecteddata.protect.aspx
using System;
using System.Security.Cryptography;
public class DataProtectionSample
{
// Create byte array for additional entropy when using Protect method.
static byte [] s_aditionalEntropy = { 9, 8, 7, 6, 5 };
public static void Main()
{
// Create a simple byte array containing data to be encrypted.
byte [] secret = { 0, 1, 2, 3, 4, 1, 2, 3, 4 };
//Encrypt the data.
byte [] encryptedSecret = Protect( secret );
Console.WriteLine("The encrypted byte array is:");
PrintValues(encryptedSecret);
// Decrypt the data and store in a byte array.
byte [] originalData = Unprotect( encryptedSecret );
Console.WriteLine("{0}The original data is:", Environment.NewLine);
PrintValues(originalData);
}
public static byte [] Protect( byte [] data )
{
try
{
// Encrypt the data using DataProtectionScope.CurrentUser. The result can be decrypted
// only by the same current user.
return ProtectedData.Protect( data, s_aditionalEntropy, DataProtectionScope.CurrentUser );
}
catch (CryptographicException e)
{
Console.WriteLine("Data was not encrypted. An error occurred.");
Console.WriteLine(e.ToString());
return null;
}
}
public static byte [] Unprotect( byte [] data )
{
try
{
//Decrypt the data using DataProtectionScope.CurrentUser.
return ProtectedData.Unprotect( data, s_aditionalEntropy, DataProtectionScope.CurrentUser );
}
catch (CryptographicException e)
{
Console.WriteLine("Data was not decrypted. An error occurred.");
Console.WriteLine(e.ToString());
return null;
}
}
public static void PrintValues( Byte[] myArr )
{
foreach ( Byte i in myArr )
{
Console.Write( "\t{0}", i );
}
Console.WriteLine();
}
}
A combination of RtlZeroMemory and VirtualLock can do what you want. VirtualLock if you want to keep the data from swapping to disk and RtlZeroMemory to ensure the memory gets zeroed (I tried to use RtlSecureZeroMemory but that doesn't seem to exist in kernel.dll) The class below will store a array of any of the built in types securely. I broke the solution up into two classes to separate out the type-agnostic code.
The first class just allocates and holds an array. It does a runtime check that the template type is a built in type. Unfortunately, I couldn't figure a way to do that at compile time.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
/// <summary>
/// Manage an array that holds sensitive information.
/// </summary>
/// <typeparam name="T">
/// The type of the array. Limited to built in types.
/// </typeparam>
public sealed class SecureArray<T> : SecureArray
{
private readonly T[] buf;
/// <summary>
/// Initialize a new instance of the <see cref="SecureArray{T}"/> class.
/// </summary>
/// <param name="size">
/// The number of elements in the secure array.
/// </param>
/// <param name="noswap">
/// Set to true to do a Win32 VirtualLock on the allocated buffer to
/// keep it from swapping to disk.
/// </param>
public SecureArray(int size, bool noswap = true)
{
this.buf = new T[size];
this.Init(this.buf, ElementSize(this.buf) * size, noswap);
}
/// <summary>
/// Gets the secure array.
/// </summary>
public T[] Buffer => this.buf;
/// <summary>
/// Gets or sets elements in the secure array.
/// </summary>
/// <param name="i">
/// The index of the element.
/// </param>
/// <returns>
/// The element.
/// </returns>
public T this[int i]
{
get
{
return this.buf[i];
}
set
{
this.buf[i] = value;
}
}
}
The next class does the real work. It tells the garbage collector to pin the array in memory. It then locks it so it doesn't swap. Upon disposal, it zeros the array and unlocks it and then tells the garbage collector to unpin it.
/// <summary>
/// Base class of all <see cref="SecureArray{T}"/> classes.
/// </summary>
public class SecureArray : IDisposable
{
/// <summary>
/// Cannot find a way to do a compile-time verification that the
/// array element type is one of these so this dictionary gets
/// used to do it at runtime.
/// </summary>
private static readonly Dictionary<Type, int> TypeSizes =
new Dictionary<Type, int>
{
{ typeof(sbyte), sizeof(sbyte) },
{ typeof(byte), sizeof(byte) },
{ typeof(short), sizeof(short) },
{ typeof(ushort), sizeof(ushort) },
{ typeof(int), sizeof(int) },
{ typeof(uint), sizeof(uint) },
{ typeof(long), sizeof(long) },
{ typeof(ulong), sizeof(ulong) },
{ typeof(char), sizeof(char) },
{ typeof(float), sizeof(float) },
{ typeof(double), sizeof(double) },
{ typeof(decimal), sizeof(decimal) },
{ typeof(bool), sizeof(bool) }
};
private GCHandle handle;
private uint byteCount;
private bool virtualLocked;
/// <summary>
/// Initialize a new instance of the <see cref="SecureArray"/> class.
/// </summary>
/// <remarks>
/// You cannot create a <see cref="SecureArray"/> directly, you must
/// derive from this class like <see cref="SecureArray{T}"/> does.
/// </remarks>
protected SecureArray()
{
}
/// <summary>
/// Gets the size of the buffer element. Will throw a
/// <see cref="NotSupportedException"/> if the element type is not
/// a built in type.
/// </summary>
/// <typeparam name="T">
/// The array element type to return the size of.
/// </typeparam>
/// <param name="buffer">
/// The array.
/// </param>
/// <returns></returns>
public static int BuiltInTypeElementSize<T>(T[] buffer)
{
int elementSize;
if (!TypeSizes.TryGetValue(typeof(T), out elementSize))
{
throw new NotSupportedException(
$"Type {typeof(T).Name} not a built in type. "
+ $"Valid types: {string.Join(", ", TypeSizes.Keys.Select(t => t.Name))}");
}
return elementSize;
}
/// <summary>
/// Zero the given buffer in a way that will not be optimized away.
/// </summary>
/// <typeparam name="T">
/// The type of the elements in the buffer.
/// </typeparam>
/// <param name="buffer">
/// The buffer to zero.
/// </param>
public static void Zero<T>(T[] buffer)
where T : struct
{
var bufHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
IntPtr bufPtr = bufHandle.AddrOfPinnedObject();
UIntPtr cnt = new UIntPtr(
(uint)buffer.Length * (uint)BuiltInTypeElementSize(buffer));
RtlZeroMemory(bufPtr, cnt);
}
finally
{
bufHandle.Free();
}
}
/// <inheritdoc/>
public void Dispose()
{
IntPtr bufPtr = this.handle.AddrOfPinnedObject();
UIntPtr cnt = new UIntPtr(this.byteCount);
RtlZeroMemory(bufPtr, cnt);
if (this.virtualLocked)
{
VirtualUnlock(bufPtr, cnt);
}
this.handle.Free();
}
/// <summary>
/// Call this with the array to secure and the number of bytes in that
/// array. The buffer will be zeroed and the handle freed when the
/// instance is disposed.
/// </summary>
/// <param name="buf">
/// The array to secure.
/// </param>
/// <param name="sizeInBytes">
/// The number of bytes in the buffer in the pinned object.
/// </param>
/// <param name="noswap">
/// True to lock the memory so it doesn't swap.
/// </param>
protected void Init<T>(T[] buf, int sizeInBytes, bool noswap)
{
this.handle = GCHandle.Alloc(buf, GCHandleType.Pinned);
this.byteCount = (uint)sizeInBytes;
IntPtr bufPtr = this.handle.AddrOfPinnedObject();
UIntPtr cnt = new UIntPtr(this.byteCount);
if (noswap)
{
VirtualLock(bufPtr, cnt);
this.virtualLocked = true;
}
}
[DllImport("kernel32.dll")]
private static extern void RtlZeroMemory(IntPtr ptr, UIntPtr cnt);
[DllImport("kernel32.dll")]
static extern bool VirtualLock(IntPtr lpAddress, UIntPtr dwSize);
[DllImport("kernel32.dll")]
static extern bool VirtualUnlock(IntPtr lpAddress, UIntPtr dwSize);
}
To use the class, simply do something like this:
using (var secret = new SecureArray<byte>(secretLength))
{
DoSomethingSecret(secret.Buffer);
}
Now, this class does two things you shouldn't do lightly, first of all, it pins the memory. This can reduce performance because the garbage collector now must work around that memory it cannot move. Second, it can lock pages in memory that the operating system may wish to swap out. This short-changes other processes on your system because now they cannot get access to that RAM.
To minimize the detrimental effects of SecureArray<T>, don't use it a lot and use it only for short amounts of time. If you want to keep the data around for longer, then you need to encrypt it. For that, your best bet is the ProtectedData class. Unfortunately, that puts your sensitive data into a non-secure byte array. The best you can do from there is do a quick copy into a SecureArray<byte>.Buffer and then a SecureArray.Zero on the sensitive byte array.
There is no "best" way to do this - you need to identify the threat you are trying to protect against in order to decide what to do or indeed if anything needs to be done.
One point to note is that, unlike a string which is immutable, you can zero out the bytes in a byte array after you've finished with them, so you won't have the same set of problems that SecureString is designed to solve.
Encrypting data could be appropriate for some set of problems, but then you will need to identify how to protect the key from unauthorized access.
I find it difficult to imagine a situation where encrypting a byte array in this way would be useful. More details of exactly what you're trying to do would help.
You could use SecureString to store the byte array.
SecureString testString = new SecureString();
// Assign the character array to the secure string.
foreach (byte b in bytes)
testString.AppendChar((char)b);
then you just reverse the process to get the bytes back out.
This isn't the only way, you can always use a MemoryBuffer and and something out of System.Security.Cryptography. But this is the only thing specifically designed to be secure in this way. All others you would have to create with the System.Security.Cryptography, which is probably the best way for you to go.
One option:
You could store the bytes in a memory stream, encrypted using any of the providers in the System.Security.Cryptography namespace.

How to lock on an integer in C#?

Is there any way to lock on an integer in C#? Integers can not be used with lock because they are boxed (and lock only locks on references).
The scenario is as follows: I have a forum based website with a moderation feature. What I want to do is make sure that no more than one moderator can moderate a post at any given time. To achieve this, I want to lock on the ID of the post.
I've had a couple of ideas so far (e.g. using a dictionary<int, object>), but I'm looking for a better and cleaner way.
Any suggestions?
I like doing it like this
public class Synchronizer {
private Dictionary<int, object> locks;
private object myLock;
public Synchronizer() {
locks = new Dictionary<int, object>();
myLock = new object();
}
public object this[int index] {
get {
lock (myLock) {
object result;
if (locks.TryGetValue(index, out result))
return result;
result = new object();
locks[index] = result;
return result;
}
}
}
}
Then, to lock on an int you simply (using the same synchronizer every time)
lock (sync[15]) { ... }
This class returns the same lock object when given the same index twice. When a new index comes, it create an object, returning it, and stores it in the dictionary for next times.
It can easily be changed to work generically with any struct or value type, or to be static so that the synchronizer object does not have to be passed around.
If it's a website then using an in-process lock probably isn't the best approach as if you need to scale the site out onto multiple servers, or add another site hosting an API (or anything else that would require another process accessing the same data to exist) then all your locking strategies are immediately ineffective.
I'd be inclined to look into database-based locking for this. The simplest approach is to use optimistic locking with something like a timestamp of when the post was last updated, and to reject updates made to a post unless the timestamps match.
I've read a lot of comments mentioning that locking isn't safe for web applications, but, other than web farms, I haven't seen any explanations of why. I would be interested in hearing the arguments against it.
I have a similar need, though I'm caching re-sized images on the hard drive (which is obviously a local action so a web farm scenario isn't an issue).
Here is a redone version of what #Configurator posted. It includes a couple features that #Configurator didn't include:
Unlocking: Ensures the list doesn't grow unreasonably large (we have millions of photos and we can have many different sizes for each).
Generic: Allows locking based on different data types (such as int or string).
Here's the code...
/// <summary>
/// Provides a way to lock a resource based on a value (such as an ID or path).
/// </summary>
public class Synchronizer<T>
{
private Dictionary<T, SyncLock> mLocks = new Dictionary<T, SyncLock>();
private object mLock = new object();
/// <summary>
/// Returns an object that can be used in a lock statement. Ex: lock(MySync.Lock(MyValue)) { ... }
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public SyncLock Lock(T value)
{
lock (mLock)
{
SyncLock theLock;
if (mLocks.TryGetValue(value, out theLock))
return theLock;
theLock = new SyncLock(value, this);
mLocks.Add(value, theLock);
return theLock;
}
}
/// <summary>
/// Unlocks the object. Called from Lock.Dispose.
/// </summary>
/// <param name="theLock"></param>
public void Unlock(SyncLock theLock)
{
mLocks.Remove(theLock.Value);
}
/// <summary>
/// Represents a lock for the Synchronizer class.
/// </summary>
public class SyncLock
: IDisposable
{
/// <summary>
/// This class should only be instantiated from the Synchronizer class.
/// </summary>
/// <param name="value"></param>
/// <param name="sync"></param>
internal SyncLock(T value, Synchronizer<T> sync)
{
Value = value;
Sync = sync;
}
/// <summary>
/// Makes sure the lock is removed.
/// </summary>
public void Dispose()
{
Sync.Unlock(this);
}
/// <summary>
/// Gets the value that this lock is based on.
/// </summary>
public T Value { get; private set; }
/// <summary>
/// Gets the synchronizer this lock was created from.
/// </summary>
private Synchronizer<T> Sync { get; set; }
}
}
Here's how you can use it...
public static readonly Synchronizer<int> sPostSync = new Synchronizer<int>();
....
using(var theLock = sPostSync.Lock(myID))
lock (theLock)
{
...
}
This option builds on the good answer provided by configurator with the following modifications:
Prevents the size of the dictionary from growing uncontrollably. Since, new posts will get new ids, your dictionary of locks will grow indefinitely. The solution is to mod the id against a maximum dictionary size. This does mean that some ids will have the same lock (and have to wait when they would otherwise not have to), but this will be acceptable for some dictionary size.
Uses ConcurrentDictionary so there is no need for a separate dictionary lock.
The code:
internal class IdLock
{
internal int LockDictionarySize
{
get { return m_lockDictionarySize; }
}
const int m_lockDictionarySize = 1000;
ConcurrentDictionary<int, object> m_locks = new ConcurrentDictionary<int, object>();
internal object this[ int id ]
{
get
{
object lockObject = new object();
int mapValue = id % m_lockDictionarySize;
lockObject = m_locks.GetOrAdd( mapValue, lockObject );
return lockObject;
}
}
}
Also, just for completeness, there is the alternative of string interning: -
Mod the id against the maximum number of interned id strings you will allow.
Convert this modded value to a string.
Concatenate the modded string with a GUID or namespace name for name collision safety.
Intern this string.
lock on the interned string.
See this answer for some information:
The only benefit of the string interning approach is that you don't need to manage a dictionary. I prefer the dictionary of locks approach as the intern approach makes a lot of assumptions about how string interning works and that it will continue to work in this way. It also uses interning for something it was never meant / designed to do.
I would personally go with either Greg's or Konrad's approach.
If you really do want to lock against the post ID itself (and assuming that your code will only ever be running in a single process) then something like this isn't too dirty:
public class ModeratorUtils
{
private static readonly HashSet<int> _LockedPosts = new HashSet<int>();
public void ModeratePost(int postId)
{
bool lockedByMe = false;
try
{
lock (_LockedPosts)
{
lockedByMe = _LockedPosts.Add(postId);
}
if (lockedByMe)
{
// do your editing
}
else
{
// sorry, can't edit at this time
}
}
finally
{
if (lockedByMe)
{
lock (_LockedPosts)
{
_LockedPosts.Remove(postId);
}
}
}
}
}
Why don't you lock on the whole posting instead just on its ID?
Coresystem at codeplex has two class for thread synchronization based on value types, for details see http://codestand.feedbook.org/2012/06/lock-on-integer-in-c.html
I doubt you should use a database or O/S level feature such as locks for a business level decision. Locks incur significant overheads when held for long times (and in these contexts, anything beyond a couple of hundred milliseconds is an eternity).
Add a status field to the post. If you deal with several therads directly, then you can use O/S level locks -- to set the flag.
You need a whole different approach to this.
Remember that with a website, you don't actually have a live running application on the other side that responds to what the user does.
You basically start a mini-app, which returns the web-page, and then the server is done. That the user ends up sending some data back is a by-product, not a guarantee.
So, you need to lock to persist after the application has returned the moderation page back to the moderator, and then release it when the moderator is done.
And you need to handle some kind of timeout, what if the moderator closes his browser after getting the moderation page back, and thus never communicates back with the server that he/she is done with the moderation process for that post.
Ideally you can avoid all the complex and brittle C# locking and replace it with database locking, if your transactions are designed correctly then you should be able to get by with DB transactions only.
Two boxed integers that happen to have the same value are completely indepent objects.
So if you wanted to do this, your idea of Dictionary would probably be the way to go. You'd need to synchronize access to the dictionary to make sure you are always getting the same instance. And you'd have the problem of the dictionary growing in size.
C# locking is for thread safety and doesn't work the way you want it to for web applications.
The simplest solution is adding a column to the table that you want to lock and when somone locks it write to the db that that column is locked.
Dont let anyone open a post in edit mode if the column is locked for editing.
Otherwise maintain a static list of locked entry Ids and compare to that before allowing an edit.
You want to make sure that a delete doesn't happen twice?
CREATE PROCEDURE RemovePost( #postID int )
AS
if exists(select postID from Posts where postID = #postID)
BEGIN
DELETE FROM Posts where postID = #postID
-- Do other stuff
END
This is pretty much SQL server syntax, I'm not familiar with MyISAM. But it allows stored procedures. I'm guessing you can mock up a similar procedure.
Anyhow, this will work for the majority of cases. The only time it will fail is if two moderators submit at almost exactly the same time, and the exists() function passes on one request just before the DELETE statement executes on another request. I would happily use this for a small site. You could take it a step further and check that the delete actually deleted a row before continuing with the rest, which would guarantee the atomicity of it all.
Trying to create a lock in code, for this use case, I consider very impractical. You lose nothing by having two moderators attempting to delete a post, with one succeeding, and the other having no effect.
You should use a sync object like this:
public class YourForm
{
private static object syncObject = new object();
public void Moderate()
{
lock(syncObject)
{
// do your business
}
}
}
But this approach shouldn't be used in a web app scenario.
public static class ConexoesDeTeste
{
private static int NumeroDeConexoes = 0;
public static void Incrementar()
{
Interlocked.Increment(ref NumeroDeConexoes);
}
public static void Decrementar()
{
Interlocked.Decrement(ref NumeroDeConexoes);
}
public static int Obter() => NumeroDeConexoes;
}

Categories