As you know, Web.Config and App.Config files are like plain readable XML files. However, it contains sensitive information such as Connection Strings, Impersonation, App Setting Keys and their values. At some point you may need to secure these sections. .NET Framework allows to make your life simple, by just executing few commands on Command Prompt or few clicks using a Enterprise Library Configuration tool, you can achieve the desired result. There is only one basic requirement you should be able to at least remotely login to the Server where you would like to make these thing. Following are few simple steps to secure web.config or app.config.
File: Web.Config using Command Prompt
1. Go to Command Prompt
2. Change Directory to C:\Windows\Microsoft.NET\Framework\v2.0.50727
3. To Encrypt a Section in Web.Cofig - type following -
aspnet_regiis -pef "<CONFIG_SECTION" "<PHYSICAL_PATH>"
i.e. aspnet_regiis -pef "connectionStrings" “C:\Inetpub\wwwroot\TestWebSite"
i.e. aspnet_regiis -pef "system.web/identity" “C:\Inetpub\wwwroot\TestWebSite"
4. Go to your website root directory, and create a File AppUser.Aspx and type the following line save it.
a. <%@ Page Language="VB" %>
<% Response.Write( System.Security.Principal.WindowsIdentity.GetCurrent().Name ) %>
b. Now, open your browser and call this page, this will show you a DOMAIN/UserName under which you website is running. Take a note of it. Now go back to command prompt.
5. Run the following command on command prompt to allow Permission to Users e.g. "NT Authority\Network Service", and the User Your Web Site is using it. run following command
aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT Authority\Network Service"
aspnet_regiis -pa "NetFrameworkConfigurationKey" "DOMAIN/USERNAME"
6. After successful completion of command, remove the AppUser.Aspx file.
7. If you ever want to decrypt the section you encrypted, use following command
aspnet_regiis -pdf "<CONFIG_SECTION" "<PHYSICAL_PATH>"
You do not need to make any code change in your application for encryption or decryption, .NET automatically does it for you.
For more details you can visit http://msdn.microsoft.com/en-us/library/ms998283.aspx
File: App.Config using Command Prompt
So what would you do to encrypt the same in case of App.Config, above command only work for Web.Config. Here is a trick – Copy the contents of App.Config into Web.Config file, or you can rename as web.config. Follow the same instructions as above, and after encryption, copy the file contents or rename it back to App.Config.
Easy Way To Encrypt/Decrypt - Web.Config/App.Config
If you have downloaded and Installed Microsoft Enterprise Library Configuration Tool, just open Web.Config or App.Config and select the section you want to encrypt, Go into Protection à Protection Provider and choose a provider you want (default is none) and save the file, you are done. BUT, you may have to follow #4 - #6, if .NET is not able to read encrypted section.
Saturday, October 04, 2008
Securing .NET Config Files
Tuesday, August 12, 2008
Communication with the underlying transaction
If you are using .NET 2.0 or higher Framework and System.Transactions Namespace to handle your transactions, chances are you may come across this error. In my application, I was using ADO.NET transaction, in stored procedure SQL Server transaction and now we decided to use a powerful transaction handler using .NET framework. If you are writing everything fresh, most likely you won’t like to mix different type of transaction handling mechanism. But what if you already have existing code and do not want to change, what to do. I tried to mix all the three kind of transactions, but it resulted in errors. Sometime, they timeout, sometime it just hanged and sometime it produced Microsoft Transaction Coordinator (MSDTC) error. So, how to resolve this problem? After spending several hours I found that one must follow following basic steps.
1. Import System.Transactions namespace in the class where you want to use distributed transaction
2. Make sure that this transaction mode is the root or mothers for all other type of transactions
3. Now you can add different type of transactions, it can be ADO.Net transaction, SQL Transaction or another child transaction using System.Transaction Namespace
4. After doing the first 3 steps, make sure you configure your machines with following options, otherwise you will come across the above error.
To fully enable MS DTC:
1. In Control Panel, open Administrative Tools, and then double-click Component Services.
2. In the left pane of Console Root, click Component Services, and then expand Computers.
3. Right-click My Computer, and then click Properties.
4. On the MSDTC tab, click Security Configuration.
5. Under Security Settings, select all of the check boxes.
6. Verify that the DTC Logon Account name is set to NT AUTHORITY\NetworkService.
If MSDTC still does not work then
1. Install MSDTC by going on command prompt and run following command: msdtc –install
2. After that you'll need to actually start the service
3. Make sure to go back in component services and follow the above step to enable MS DTC.
4. Windows Firewall –Make sure C:\Windows\System32\MSDTC.exe is added in Exceptions list of Windows Firewall
If MSDTC still does not work, reboot the machine.
Other Helpful links:
http://support.microsoft.com/kb/817064
http://support.microsoft.com/kb/908620
http://msdn.microsoft.com/en-us/library/ms936442.aspx
http://www.andornot.com/about/developerblog/2008/05/when-distributed-transactions-go-boing.aspx
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=230390&SiteID=1
If you MSDTC still does not work, download the following tool and you can see where it is failingYou need to make sure that these options are enabled on all participating machines (Web Server, App Server, SQL Server etc)
Example:Public Sub MainMethod()Dim tranOptions As New TransactionOptions()tranOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommittedtranOptions.Timeout = New TimeSpan(0, 2, 0)Using topMostScope As New TransactionScope(TransactionScopeOption.Required, tranOptions)Call Method1UsingAdo_Net_Transaction()Call Method2UsingSql_Server_Transaction()Call Method3UsingChildTranScope()topMostScope.Complete()End UsingEnd Sub
Thursday, May 29, 2008
Secure Query String using Symmetric Cryptography
It is important to secure information on the web specially when transferring data from one page to another. Some information you may not want to make it readable by end user. Microsoft .NET provides Cryptography namespace which can be easily utilized for this purpose. The following example contains a simple class containing Encryption and Decryption method. It supports 2 types – DESC and Rijndael. Symmetric type and encryption key can be configured easily through .config file.
Imports SystemImports System.IOImports System.TextImports System.Security.CryptographyImports System.Configuration''' <summary>''' Custom Encryption Class''' Author: Vishwa''' Date :05/28/08''' Purpose: To Encrypt and Decrypt the Data''' Design Pattern : Singleton''' </summary>''' <remarks>''' This class implements a Base 64 encryption and decryption Using Symetric''' IMPT: Config File will contain 2 keys and its value - SymmetricType and SymmetricKey''' </remarks>Public NotInheritable Class RegCryptographerPrivate Shared _instance As New RegCryptographer#Region "Constructor"Private Sub New()End Sub#End Region#Region "Public Methods"Public Shared Function DecryptQueryString(ByVal stringToDecrypt As String) As StringReturn DecryptSymmetric(stringToDecrypt.Replace(" ", "+"))End FunctionPublic Shared Function EncryptQueryString(ByVal stringToEncrypt As String) As StringReturn EncryptSymmetric(stringToEncrypt)End Function#End Region#Region "Custom Cryptography"Private Shared _key() As Byte = {}Private Shared _IV() As Byte = {}Private Shared _symmetricKey As String = String.Empty#Region "Rijndael Encryption/Decryption"Public Shared Function DecryptSymmetric(ByVal stringToDecrypt As String) As StringIf SymmetricType = "Rijndael" ThenReturn DecryptSymmetricRijndael(stringToDecrypt)ElseReturn DecryptSymmetricDESC(stringToDecrypt)End IfEnd FunctionPublic Shared Function EncryptSymmetric(ByVal stringToEncrypt As String) As StringIf SymmetricType = "Rijndael" ThenReturn EncryptSymmetricRijndael(stringToEncrypt)ElseReturn EncryptSymmetricDESC(stringToEncrypt)End IfEnd FunctionPrivate Shared Function DecryptSymmetricRijndael(ByVal stringToDecrypt As String) As StringTryDim inputByteArray(stringToDecrypt.Length) As ByteDim rijndael As New RijndaelManaged()rijndael.GenerateIV()'rijndael.GenerateKey()'_key = rijndael.Key_IV = rijndael.IVrijndael.KeySize = 128rijndael.BlockSize = 128rijndael.Mode = CipherMode.ECBrijndael.Padding = PaddingMode.PKCS7_key = System.Text.Encoding.UTF32.GetBytes(SymmetricKey)inputByteArray = Convert.FromBase64String(stringToDecrypt)Dim decryptor As ICryptoTransform = rijndael.CreateDecryptor(_key, _IV)Dim msDecrypt As New MemoryStream()Dim csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write)csDecrypt.Write(inputByteArray, 0, inputByteArray.Length)csDecrypt.FlushFinalBlock()Dim encoding As System.Text.Encoding = System.Text.Encoding.UTF8Return encoding.GetString(msDecrypt.ToArray())Catch e As ExceptionReturn e.MessageEnd TryEnd FunctionPrivate Shared Function EncryptSymmetricRijndael(ByVal stringToEncrypt As String) As StringTryDim rijndael As New RijndaelManaged()rijndael.GenerateIV()'rijndael.GenerateKey()'_key = rijndael.Key_IV = rijndael.IV_key = System.Text.Encoding.UTF32.GetBytes(SymmetricKey)rijndael.KeySize = 128rijndael.BlockSize = 128rijndael.Mode = CipherMode.ECBrijndael.Padding = PaddingMode.PKCS7Dim encryptor As ICryptoTransform = rijndael.CreateEncryptor(_key, _IV)Dim inputByteArray() As Byte = Encoding.UTF8.GetBytes(stringToEncrypt)Dim msEncrypt As New MemoryStream()Dim csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)csEncrypt.Write(inputByteArray, 0, inputByteArray.Length)csEncrypt.FlushFinalBlock()Return Convert.ToBase64String(msEncrypt.ToArray())Catch e As ExceptionReturn e.MessageEnd TryEnd Function#End Region#Region "DESC Encryption/DeCryption"Private Shared _symmetricType As String = String.EmptyPrivate Shared Function DecryptSymmetricDESC(ByVal stringToDecrypt As String) As StringDim inputByteArray(stringToDecrypt.Length) As ByteTryinputByteArray = Convert.FromBase64String(stringToDecrypt)Dim des As New DESCryptoServiceProvider()des.GenerateIV()_IV = des.IV_key = System.Text.Encoding.UTF8.GetBytes(SymmetricKey)Dim ms As New MemoryStream()Dim cs As New CryptoStream(ms, des.CreateDecryptor(_key, _IV), CryptoStreamMode.Write)cs.Write(inputByteArray, 0, inputByteArray.Length)cs.FlushFinalBlock()Dim encoding As System.Text.Encoding = System.Text.Encoding.UTF8Return encoding.GetString(ms.ToArray())Catch e As ExceptionReturn e.MessageEnd TryEnd FunctionPrivate Shared Function EncryptSymmetricDESC(ByVal stringToEncrypt As String) As StringTryDim des As New DESCryptoServiceProvider()des.GenerateIV()_IV = des.IV_key = System.Text.Encoding.UTF8.GetBytes(SymmetricKey)Dim inputByteArray() As Byte = Encoding.UTF8.GetBytes(stringToEncrypt)Dim ms As New MemoryStream()Dim cs As New CryptoStream(ms, des.CreateEncryptor(_key, _IV), CryptoStreamMode.Write)cs.Write(inputByteArray, 0, inputByteArray.Length)cs.FlushFinalBlock()Return Convert.ToBase64String(ms.ToArray())Catch e As ExceptionReturn e.MessageEnd TryEnd Function#End Region#Region "Properties"Private Shared ReadOnly Property SymmetricType() As StringGetIf String.IsNullOrEmpty(_symmetricType) ThenTry_symmetricType = ConfigurationManager.AppSettings.Item("SymmetricType")Catch ex As Exception_symmetricType = "Rijndael"End TryIf String.IsNullOrEmpty(_symmetricType) Then _symmetricType = "Rijndael"End IfReturn _symmetricTypeEnd GetEnd PropertyPrivate Shared ReadOnly Property SymmetricKey() As StringGetIf String.IsNullOrEmpty(_symmetricKey) ThenTry_symmetricKey = ConfigurationManager.AppSettings.Item("SymmetricKey")Catch ex As Exception_symmetricKey = "DIffTkey"End TryIf String.IsNullOrEmpty(_symmetricKey) Then _symmetricKey = "DIffTkey"End IfReturn Left(_symmetricKey, 8)End GetEnd Property#End Region#End RegionEnd Class
Friday, April 18, 2008
Error: System.ServiceModel.Channels
Recently I came across interesting error messages while calling a WCF Service Hosted in IIS 6.0 on Windows 2003 Server. From the error message, I could not figure out the real cause. But after doing some research and changing few configuration information and changing the code, it appears that these solutions fixed these errors.
Errors
Thursday, April 17, 2008
Error: Could not establish trust relationship for the SSL/TLS secure channel with authority
I got this error when calling a WCF Service over HTTPS. A Similar error can also occurs when you try calling a web service programmatically over SSL (HTTPS) and certificate is either not valid or Certificate is attached to a domain and you are not using the domain name but the machine name or IP address. So, what to do in that case if you don’t care about certificate and would like to accept all certificates. I found that it can be done using one of two ways.
Main Class – Where you are calling the Web Service, add following Import StatementsImports System.Security.Cryptography.X509CertificatesImports System.Net.SecurityImports System.NetPublic Class MyWebServiceCallPublic Sub CallServiceUsingFunction()'Instanciate the Service here'Set all paramaters which you need to pass'Before You call the ServiceServicePointManager.ServerCertificateValidationCallback = AddressOf TrustAllCertificatesCallback'Call your service Now.......End SubPublic Shared Function TrustAllCertificatesCallback(ByVal sender As Object, ByVal cert As X509Certificate, _ByVal chain As X509Chain, ByVal errors As SslPolicyErrors) As BooleanReturn TrueEnd FunctionPublic Sub CallServiceUsingClass()'Instanciate the Service here'Set all paramaters which you need to pass'Before You call the ServiceDim CertOverride As New CertificateOverrideServicePointManager.ServerCertificateValidationCallback = AddressOf CertOverride.RemoteCertificateValidationCallback'Call your service Now.......End SubEnd ClassCertificateOverride Class - An Alternate OptionPublic Class CertificateOverridePublic Function RemoteCertificateValidationCallback(ByVal sender As Object, ByVal certificate As X509Certificate, ByVal chain As X509Chain, _ByVal sslPolicyErrors As SslPolicyErrors) As BooleanReturn TrueEnd FunctionEnd Class
Saturday, April 05, 2008
Make a .NET Component accessible in Classic ASP or VB6
I came across a situation again to use exactly same .NET component as COM component in classic ASP page. I had totally forgotten these steps but finally managed to make it work. Later, I thought to put these steps together on my blog, so that if anyone else also don’t know or forget these steps, this will help.
b. Create "application.config" with needed section(s) from Web.Config
2. Go to COM+ package through Component Services
a. Add your type library file (.tlb ) in your package
b. In Properties of the Package go to "Activation" tab and change Application Root Directory to <APP_PATH>\bin
Working Example: For example let’s create a Class Library Project – Vishwa.Example.ComTest
1: Imports System
2: Imports System.Reflection
3: Imports System.Runtime.InteropServices
4: Imports System.EnterpriseServices
5:
6: #Region "Assembly Attributes"
7: <Assembly: AssemblyTitle("Vishwa.Example.ComTest")>
8: <Assembly: AssemblyDescription("")>
9: <Assembly: AssemblyCompany("")>
10: <Assembly: AssemblyProduct("Vishwa.Example.ComTest")>
11: <Assembly: AssemblyCopyright("Copyright © 2008")>
12: <Assembly: AssemblyTrademark("")>
13: <Assembly: ApplicationName("ComTest")>
14: <Assembly: ApplicationActivation(ActivationOption.Server)>
15: <Assembly: ApplicationAccessControl(False, AccessChecksLevel:=AccessChecksLevelOption.ApplicationComponent)>
16: <Assembly: ComVisible(True)>
17: <Assembly: Guid("1e411fb7-d23f-4246-99da-4200e999e030")>
18: <Assembly: AssemblyVersion("1.0.0.0")>
19: <Assembly: AssemblyFileVersion("1.0.0.0")>
20: #End Region
1: Public Class TestProcess
2:
3: #Region "Default Public Constructor"
4: Public Sub New()
5: End Sub
6: #End Region
7:
8: #Region "Public Methods"
9:
10: Public Function Add(ByVal value1 As Integer, ByVal value2 As Integer) As Integer
11: Return value1 + value2
12: End Function
13:
14: #End Region
15:
16: End Class
Tuesday, March 25, 2008
Implementing WCF Service Part 5 - Fault Contract
In WCF, there are five major contracts – Service Contract, Operation Contract, Data Contract, Fault Contract and Message Contract. In my previous examples I used first three. In this example, I will implement the Fault Contract. I am not very fond of using Message Contract as some guidelines suggest using the least or based on requirement, however you cannot get away from the first four contracts. In the event of Fault (exception), WCF throws a fault containing detail error message which you may not like to be passed back to the caller. In other words, this example focuses on how to hide full error details and provide a custom error code, message and details. You can use multiple Fault Contracts on one Operation Contract in similar way. This example provides a simple and generic way to handle Faults.
In order to show this example, I will add or modify following classes.
1. ErrorResponse Class - New<DataContract(Name:="ErrorResponse", Namespace:="http://http://schemas.vishwamohan.net/2008/03/ErrorResponse")> _Public Class ErrorResponse#Region "Public Fields"<DataMember(Name:="Code", Order:=0)> _
Public Code As String = "Error"<DataMember(Name:="Message", Order:=1)> _
Public Message As String = "Sorry! An exception occured."<DataMember(Name:="Details", Order:=2)> _
Public Details As String = "Please contact support."#End Region
#Region "Constructors"Public Sub New()End SubPublic Sub New(ByVal code As String, ByVal message As String, ByVal details As String)Me.Code = code
Me.Message = message
Me.Details = details
End Sub#End Region
End Class
2. ICustomerService.vb Class – Modifying Existing Operation Contract, by adding Fault Contract<FaultContract(GetType(ErrorResponse))> _
<OperationContract(Name:="GetCustomer")> _
Function GetCustomer(ByVal ID As Integer) As Customer3. CustomerService.svc – Modifying Existing Service Contract, by Handling the Exception and Throwing FaultPublic Function GetCustomer(ByVal ID As Integer) As Customer Implements ICustomerService.GetCustomerTry
Return ServiceHelper.GetCustomerData(ID)
Catch ex As ExceptionThrow New FaultException(Of ErrorResponse)(New ErrorResponse, ex.Message)'or
'Throw New FaultException(Of ErrorResponse)(New ErrorResponse("ErrorCode", "ErrorMessage", "ErrorDetails"), ex.Message)
End TryEnd Function
Note: The value of for reason which is provided by ex.Message is optional, but if you will not provide, WCF Service will generate a message that creator of this fault did not specify the reason. So it will be advisable to pass a proper message in reason.