Encrypting your web.config

Ever wanted to protect certain sections of your web.config?

In .net 2.0 we're provided with a few standard protection providers, and the ability to write our own.
RSAProtectedConfigurationProvider : Default provider that uses RSA public key encryption to encrypt/decrypt sections.

DPAPIProtectedConfigurationProvider : Provider that uses the Windows Data Protection API (DPAPI) to encrypt/decrypt sections.

These providers can be invoked using a command-line tool, called aspnet_regiis (if you've got full access to your webserver). You will notice two commands, the first one calling the -pa attribute, this is your asp.net application identity, it gives your web application rights to the configuration store.

If you're unsure about which account you're application is using, you can always output the WindowsIdentity.GetCurrent().Name property somewhere, or simply check it out in IIS.

The second command using the -pe attribute does the actual encryption.

 
aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT Authority\Network Service"
aspnet_regiis -pe "connectionStrings" -app "/WebApplication"
 

Or this can be done by writing a few simple lines of code (usually needed in a shared hosting environment, where you've got certain restrictions)

In the code sample you'll find below you simply need to pass the name of the section you wish to encrypt/decrypt, eg appSettings, connectionStrings

Note that not all sections can be encrypted in this manner, some examples are
 
<processModel>, <runtime>, <mscorlib>, <startup>, <system.runtime.remoting>,
                    <protectedData>, <satelliteassemblies>, <cryptographySettings>,
                    <cryptoNameMapping>, and <cryptoClasses>
 


Generally you would want to encrypt as little of the sections as possible (only ones containing sensitive settings), since there is some performance overhead (.net decrypts keys automatically in memory when needed, so that you dont need to decrypt a section whenever you need to use it in your application).

C#

 
// Namespaces you'll need
using System.Configuration;
using System.Web.Configuration;
 
private void EncryptSection(string sectionName)
{
    Configuration Config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
    SectionInformation Section = Config.GetSection(sectionName).SectionInformation;
 
    if (!Section.IsProtected)
    {
        Section.ProtectSection("RsaProtectedConfigurationProvider");
        Section.ForceSave = true;
        Config.Save(ConfigurationSaveMode.Modified);
    }
}
 
private void DecryptSection(string sectionName)
{
    Configuration Config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);        
    SectionInformation Section = Config.GetSection(sectionName).SectionInformation;
 
    if (Section.IsProtected)
    {
        Section.UnprotectSection();
        Section.ForceSave = true;
        Config.Save(ConfigurationSaveMode.Modified);
    }
}
 

VB.net

 
'Namespaces you'll need
Imports System.Web.Configuration
 
Private Sub EncryptSection(ByVal sectionName As String)
    Dim Config As Configuration = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath)
    Dim Section As SectionInformation = Config.GetSection(sectionName).SectionInformation
    If Not Section.IsProtected Then
        Section.ProtectSection("RsaProtectedConfigurationProvider")
        Section.ForceSave = True
        Config.Save(ConfigurationSaveMode.Modified)
    End If
End Sub
 
Private Sub DecryptSection(ByVal sectionName As String)
    Dim Config As Configuration = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath)
    Dim Section As SectionInformation = Config.GetSection(sectionName).SectionInformation
    If Section.IsProtected Then
        Section.UnprotectSection()
        Section.ForceSave = True
        Config.Save(ConfigurationSaveMode.Modified)
    End If
End Sub
 


If everything worked out as planned, you'll end up with something similar to this in your web.config.

 
<appSettings configProtectionProvider="RsaProtectedConfigurationProvider">
    <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
        xmlns="http://www.w3.org/2001/04/xmlenc#">
        <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
        <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
                <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
                <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                    <KeyName>Rsa Key</KeyName>
                </KeyInfo>
                <CipherData>
                    <CipherValue>GCe06wmlf/snuz4o7cyNpTJ+z8gBXSv89De8GkcWlNSiFzRFryxM83gUzJJzs/ADotejMnnp0IukSdXKiFzelsBmShm7mi/E8RhSZa4Pb3NXFhqHxHnP3tASMeV98dJfKTSwC3Ct1/zRYqUBN3XR3ndnYLYvcbqtBPdM+Kl/0yY=</CipherValue>
                </CipherData>
            </EncryptedKey>
        </KeyInfo>
        <CipherData>
            <CipherValue>nl7/3WpzEN/wHZgJwW35IQsWJjdvrkzvdO94MoPn/HK8LA94zV8yyYjJevvC+x6t5U4YOAqmSfc0pGA/FqPlbpYiuqjQ/HYMT3lRNAaHOk0=</CipherValue>
        </CipherData>
    </EncryptedData>
</appSettings>
 

Things can get a little bit more complicated once you find yourself in a webfarm for example, where you'd need to export your RSA keys (since the actual key used for decrypting the ciphers gets stored on the server) and deploy it to your farms etc - or perhaps rather simply do it programatically, using code similar to which is provided in this blog.

Post/View comments
 

Moving items between listboxes in ASP.net/PHP example

Ever wanted to move items between two listboxes in ASP.net (or PHP for that matter)?



Someone wanted the exact same thing on codeproject.com a while ago but I didn't give much thought to it, until someone at work asked me how to do it - since he wasn't able to find a viable solution on the internet.

The solution I scripted wasn't as simple as I thought, nor would have liked it to be, my feeling was that one would be able to alter the two listboxes easily using javascript and simply "harvest" the changes (from the Request variables) when its submitted to the server.

The reality however is that only items selected(or highlighted) in the listboxes, will be returned to the server, not the state of the listboxes - so we need to somehow send the state of the listboxes along with the page request.

What I did was, I wrote a javascript script, that serialized the contents of the listboxes as xml to a hiddenfield on the page - whenever you submit the form to the server, a xml string containing the state of the listboxes get sent along - which one can easily process server side (which I will show you just in a while).

You can download the full working source code here, contains sources for ASP.net(C# & VB.NET) and PHP source code.

 
function move(fromID, toID, containerID)
{
    var from = document.getElementById(fromID);
    var to = document.getElementById(toID);
 
    for (var i = 0; i < from.options.length; i++)
    {
        if (from.options[i].selected)
        {					
            to.options.add(new Option(from.options[i].text,from.options[i].value))
            from.remove(i--);
        }
    }
 
    var container = document.getElementById(containerID);	
    container.value = escape("<listboxes>" + serialize(from) + serialize(to) + "</listboxes>");
}
 
function serialize(dropdown)
{	
    var value = '<' + dropdown.id + '>';	
    for (var i = 0; i < dropdown.options.length; i++)
    {
        value+= '<option><key><![CDATA[' + dropdown.options[i].text + ']]></key><value><![CDATA[' + dropdown.options[i].value + ']]></value></option>';
    }
    value+='</' + dropdown.id + '>';
    return value
}
 
function unselect(listbox)
{
    document.getElementById(listbox).selectedIndex=-1;
}
 


Tying it all together (javascript with some .net code), you can easily write yourself an usercontrol, like I did in my example, or create a composite control.

The .net code below is pretty straighforward, you'll noticed two publicly exposed ListBox properties (lstFrom, lstTo), giving us easy access to the listboxes.

If you really need to, you can easily add third, forth listboxes (with slight changes to the javascript code)

The PHP code is quite a bit more involved, I had to create a few classes that give similiar control of what you would expect from an ASP.NET server side control. There is a lot easier ways to do this, but I believe this is a fairly manageable approach.

C#

 
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
 
public partial class ListPicker : System.Web.UI.UserControl
{
    private XmlDocument _xmlDocument = new XmlDocument();
 
    public ListBox fromListBox
    {
        get
        {
            return lstFrom;
        }
    }
 
    public ListBox toListBox
    {
        get
        {
            return lstTo;
        }
    }
 
    private void PopulateListBox(ListBox listBox)
    {
        listBox.Items.Clear();
        XmlNodeList nodes = _xmlDocument.SelectNodes("listboxes/" + listBox.ClientID + "/option");
        foreach (XmlNode node in nodes)
        {
            listBox.Items.Add(new ListItem(node["key"].InnerText, node["value"].InnerText));
        }
    }
 
    private void PopulateListBoxes()
    {        
        _xmlDocument.LoadXml(HttpUtility.UrlDecode(hdnDropdowns.Value));
        PopulateListBox(lstFrom);
        PopulateListBox(lstTo);
    }
 
    protected void Page_Load(object sender, EventArgs e)
    {
        Page.ClientScript.RegisterClientScriptInclude("listboxjs", Page.TemplateSourceDirectory + "/js/listbox.js");
 
        if (!IsPostBack)
        {
            String movejs = "move('{0}','{1}','{2}')";
            String unselectjs = "unselect('{0}')";
            lstFrom.Attributes["onclick"] = String.Format(unselectjs, lstTo.ClientID);
            lstTo.Attributes["onclick"] = String.Format(unselectjs, lstFrom.ClientID);
            btnTo.Attributes["onclick"] = String.Format(movejs, lstFrom.ClientID, lstTo.ClientID, hdnDropdowns.ClientID);
            btnFrom.Attributes["onclick"] = String.Format(movejs, lstTo.ClientID, lstFrom.ClientID, hdnDropdowns.ClientID);
        }
        else
        {
            if (!(String.IsNullOrEmpty(hdnDropdowns.Value)))
            {
                PopulateListBoxes();
            }
        }
    }
}
 

VB.net

 
Imports System.Xml
 
Partial Class ListPicker
    Inherits System.Web.UI.UserControl
 
    Private _xmlDocument As New XmlDocument()
 
    Public ReadOnly Property fromListBox() As ListBox
        Get
            Return lstFrom
        End Get
    End Property
 
    Public ReadOnly Property toListBox() As ListBox
        Get
            Return lstTo
        End Get
    End Property
 
    Private Sub PopulateListBox(ByVal lstBox As ListBox)
        lstBox.Items.Clear()
        Dim nodes As XmlNodeList = _xmlDocument.SelectNodes("listboxes/" + lstBox.ClientID + "/option")
        For Each node As XmlNode In nodes
            lstBox.Items.Add(New ListItem(node.Item("key").InnerText, node.Item("value").InnerText))
        Next
    End Sub
 
    Private Sub PopulateListBoxes()
        _xmlDocument.LoadXml(HttpUtility.UrlDecode(hdnDropdowns.Value))
        PopulateListBox(lstFrom)
        PopulateListBox(lstTo)
    End Sub
 
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Page.ClientScript.RegisterClientScriptInclude("listboxjs", Page.TemplateSourceDirectory & "/js/listbox.js")
 
        If Not IsPostBack Then
            Dim movejs As String = "move('{0}','{1}','{2}')"
            Dim unselectjs As String = "unselect('{0}')"
 
            lstFrom.Attributes("onclick") = String.Format(unselectjs, lstTo.ClientID)
            lstTo.Attributes("onclick") = String.Format(unselectjs, lstFrom.ClientID)
            btnTo.Attributes("onclick") = String.Format(movejs, lstFrom.ClientID, lstTo.ClientID, hdnDropdowns.ClientID)
            btnFrom.Attributes("onclick") = String.Format(movejs, lstTo.ClientID, lstFrom.ClientID, hdnDropdowns.ClientID)
        Else
            If Not String.IsNullOrEmpty(hdnDropdowns.Value) Then
                PopulateListBoxes()
            End If
        End If
    End Sub
End Class
 

PHP

 
<?php
 
require_once("controls.php");
require_once("listbox.php");
 
class listpicker extends controls
{
    var $lstFrom;
    var $lstTo;
    var $deserializable;
 
    function listpicker($id)
    {
        $this->attributes['id'] = $id;
        $this->lstFrom = new listbox($id.'_lstFrom');
        $this->lstFrom->attributes['style'] = 'width:200px';
        $this->lstFrom->attributes['onclick'] = "unselect('".$id."_lstTo')";	
        $this->lstTo = new listbox($id.'_lstTo');
        $this->lstTo->attributes['style'] = 'width:200px';
        $this->lstTo->attributes['onclick'] = "unselect('".$id."_lstFrom')";
 
        if ($_REQUEST[$id.'$hdnDropdowns'])
        {
            $this->deserializable = true;
            $this->xml(urldecode($_REQUEST[$id.'$hdnDropdowns']));			
        }	
    }
 
    function render()
    {	
    $id = $this->attributes['id'];
    $html='<table>
                <tr>
                    <td>'
                        .$this->lstFrom->render().
                    '</td>
                    <td>
                        <input id="btnTo" type="button" value=">>" onclick="move(\''.$id.'_lstFrom\',\''.$id.'_lstTo\',\''.$id.'_hdnDropdowns\')" />
                            <br />
                        <input id="btnFrom" type="button" value="<<" onclick="move(\''.$id.'_lstTo\',\''.$id.'_lstFrom\',\''.$id.'_hdnDropdowns\')" />
                    </td>
                    <td>'		
                        .$this->lstTo->render().
                    '</td>
                </tr>
            </table>
	        <input type="hidden" ID="'.$id.'_hdnDropdowns" name="'.$id.'$hdnDropdowns" />';		
    return $html;
    }
 
    function xml($text) 
    {		
        $id = $this->attributes['id'];
        $parser = xml_parser_create();
        xml_parse_into_struct($parser, $text, $vals);
        xml_parser_free($parser);
        $tag = "";
 
        for($i = 0; $i < count($vals); $i++)
        {	
            switch($vals[$i]['tag'])
            {
                case strtoupper($id.'_lstFrom') : $tag = "lstFrom";	break;
                case strtoupper($id.'_lstTo') : $tag = "lstTo";	break;
            }
 
            if (($tag) && ($vals[$i]['tag'] == "KEY"))
            {
                $this->{$tag}->addItem($vals[$i]['value'], $vals[$i+1]['value']);					
            }
        }
    }
}
 
?>
 

Post/View comments
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27