Sunday, February 28, 2010

Use the 404 page to find missing children

Scott Hanselman blogged about an excellent idea that he had seen where a PHP developer had created a 404 page that displayed a list of missing children.

In my opinion this is a great idea – as people always end up seeing a 404 page and by displaying a list of missing kids – who knows, we might just be able to find a missing kid. Scott created a 404 page using only Javascript (the original used server side PHP). Scott’s implementation uses the ASP.Net AJAX Library and specifically uses the DataView control.

I wanted to make a few modifications to Scott’s implementation of the 404 page:

  1. Make the page so that it is a lot more easier for someone to download the code and reuse it.
  2. Use only JQuery
  3. Geolocate the user using their IP address.

The reason I wanted to use only JQuery was that I didnt think it was necessary to download an extra javascript library just to display the data, when JQuery could do it all. (In addition, I used direct references to jQuery – instead of the $, as it makes it easier to include on a DotNetNuke site).

The biggest improvement in my opinion is the use of the client’s IP address to geo-locate them. By geo-locating the end user, I can customize the list of children to the state from where the user is. This in my opinion increases the probability of finding missing children as the list is smaller and more relevant to the user.

For geo-locating the user, I use two techniques. Because JQuery is loaded using Google’s content delivery network I can use Google’s API to try and determine the location of the user. If this fails (and it does many times), I use IPInfoDB’s webservice to try and geo-locate the user.

image

Here is where you can take a look at my implementation of the 404 page with geolocation capabilities: http://www.aggregatedintelligence.com/404.html

Note:

As I use the Google API, you will need to generate a Google API key to use the code on a webserver (if you are testing – you dont need to do anything). To get the key go to : http://code.google.com/apis/ajaxsearch/signup.html. Once you generate the key, plug it into the file at line: 33 (or search for “YourGoogleApiKeyHere” to find the location).

Download the 404 page from: Google Docs FileShare

Friday, February 26, 2010

Encrypting/Decrypting using DigitalCertificates using C#

Here is some quick code I wrote up that allows you to perform Asymmetric encryption using the RSA algorithm. The keys used are from a digital certificate stored in the local user’s cert store (the code to create a certificate for testing is also included in the sample.

using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace X509Certificate2_Encryption_Example
{
    class X509Certificate2_Cryptographer
    {
        //creating the certificate
        //makecert -r -pe -n "CN=WWW.AGGREGATEDINTELLIGENCE.COM" -b 01/01/2005 -e 01/01/2020 -sky exchange -ss my
        public static void Main()
        {
            try
            {
                X509Certificate2 x509_2 = LoadCertificate(StoreLocation.CurrentUser, "CN=WWW.AGGREGATEDINTELLIGENCE.COM");
                //DisplayX509CertificateInfo(x509_2);
                
                string plaintext = "HelloWorld";
                Console.WriteLine("Plain text: " + plaintext + Environment.NewLine);
                
                string encryptedstring = Encrypt(x509_2, plaintext);
                Console.WriteLine("Encrypted text: " + Environment.NewLine + encryptedstring + Environment.NewLine);
                
                string decryptedstring = Decrypt(x509_2, encryptedstring);
                Console.WriteLine("decrypted text: " + decryptedstring + Environment.NewLine);                
            }
            catch (Exception e)
            {
                Console.WriteLine("Error: {0}", e.Message);
            }
            Console.ReadLine();
        }
        
        public static X509Certificate2 LoadCertificate(StoreLocation storeLocation, string certificateName )
        {
            X509Store store = new X509Store(storeLocation);
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certCollection = store.Certificates;
            X509Certificate2 x509 = null;
            foreach (X509Certificate2 c in certCollection)
            {
                if (c.Subject == certificateName)
                {
                    x509 = c;
                    break;
                }
            }
            if (x509 == null)
                Console.WriteLine("A x509 certificate for " + certificateName + " was not found");
            store.Close();
            return x509;
        }
        
        public static void DisplayX509CertificateInfo(X509Certificate2 x509)
        {
            if (x509 == null)
                throw new Exception("A x509 certificate must be provided");
                
            Console.WriteLine("{0}Subject: {1}{0}", Environment.NewLine,x509.Subject);
            Console.WriteLine("{0}Issuer: {1}{0}", Environment.NewLine,x509.Issuer);
            Console.WriteLine("{0}Version: {1}{0}", Environment.NewLine,x509.Version);
            Console.WriteLine("{0}Valid Date: {1}{0}", Environment.NewLine,x509.NotBefore);
            Console.WriteLine("{0}Expiry Date: {1}{0}", Environment.NewLine,x509.NotAfter);
            Console.WriteLine("{0}Thumbprint: {1}{0}", Environment.NewLine,x509.Thumbprint);
            Console.WriteLine("{0}Serial Number: {1}{0}", Environment.NewLine,x509.SerialNumber);
            Console.WriteLine("{0}Friendly Name: {1}{0}",Environment.NewLine,x509.PublicKey.Oid.FriendlyName);
            Console.WriteLine("{0}Public Key Format: {1}{0}",Environment.NewLine,x509.PublicKey.EncodedKeyValue.Format(true));
            Console.WriteLine("{0}Raw Data Length: {1}{0}", Environment.NewLine,x509.RawData.Length);
            Console.WriteLine("{0}Certificate to string: {1}{0}", Environment.NewLine,x509.ToString(true));

            Console.WriteLine("{0}Certificate to XML String: {1}{0}",Environment.NewLine,x509.PublicKey.Key.ToXmlString(false));
        }
        
        public static string Encrypt(X509Certificate2 x509, string stringToEncrypt)
        {
            if (x509 == null || string.IsNullOrEmpty(stringToEncrypt))
                throw new Exception("A x509 certificate and string for encryption must be provided");
                
            RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)x509.PublicKey.Key;
            byte[] bytestoEncrypt = ASCIIEncoding.ASCII.GetBytes(stringToEncrypt);
            byte[] encryptedBytes = rsa.Encrypt(bytestoEncrypt, false);
            return Convert.ToBase64String(encryptedBytes);
        }
        
        public static string Decrypt(X509Certificate2 x509, string stringTodecrypt)
        {
            if (x509 == null || string.IsNullOrEmpty(stringTodecrypt))
                throw new Exception("A x509 certificate and string for decryption must be provided");
                
            if (!x509.HasPrivateKey)
                throw new Exception("x509 certicate does not contain a private key for decryption");
                
            RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)x509.PrivateKey;
            byte[] bytestodecrypt = Convert.FromBase64String(stringTodecrypt);
            byte[] plainbytes = rsa.Decrypt(bytestodecrypt, false);
            System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
            return enc.GetString(plainbytes);
        }
    }
}

Notes:

RSACryptoServiceProvider: http://msdn.microsoft.com/en-us/library/bfsktky3(VS.80).aspx

MakeCert: http://msdn.microsoft.com/en-us/library/bfsktky3(VS.80).aspx

X509Certificate2 Class: http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.aspx

Example of Rijndael based encryption/decryption in C#

from: http://www.obviex.com/samples/Code.aspx?Source=EncryptionCS&Title=Symmetric%20Key%20Encryption&Lang=C%23

Uses plain text for its initialization vector and password. Which means that you can store those values in your web.config (which you would obviously have to encrypt – see exportable encryptio)

///////////////////////////////////////////////////////////////////////////////
// SAMPLE: Symmetric key encryption and decryption using Rijndael algorithm.
// 
// To run this sample, create a new Visual C# project using the Console
// Application template and replace the contents of the Class1.cs file with
// the code below.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// 
// Copyright (C) 2002 Obviex(TM). All rights reserved.
// 
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;

/// <summary>
/// This class uses a symmetric key algorithm (Rijndael/AES) to encrypt and 
/// decrypt data. As long as encryption and decryption routines use the same
/// parameters to generate the keys, the keys are guaranteed to be the same.
/// The class uses static functions with duplicate code to make it easier to
/// demonstrate encryption and decryption logic. In a real-life application, 
/// this may not be the most efficient way of handling encryption, so - as
/// soon as you feel comfortable with it - you may want to redesign this class.
/// </summary>
public class RijndaelSimple
{
    /// <summary>
    /// Encrypts specified plaintext using Rijndael symmetric key algorithm
    /// and returns a base64-encoded result.
    /// </summary>
    /// <param name="plainText">
    /// Plaintext value to be encrypted.
    /// </param>
    /// <param name="passPhrase">
    /// Passphrase from which a pseudo-random password will be derived. The
    /// derived password will be used to generate the encryption key.
    /// Passphrase can be any string. In this example we assume that this
    /// passphrase is an ASCII string.
    /// </param>
    /// <param name="saltValue">
    /// Salt value used along with passphrase to generate password. Salt can
    /// be any string. In this example we assume that salt is an ASCII string.
    /// </param>
    /// <param name="hashAlgorithm">
    /// Hash algorithm used to generate password. Allowed values are: "MD5" and
    /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
    /// </param>
    /// <param name="passwordIterations">
    /// Number of iterations used to generate password. One or two iterations
    /// should be enough.
    /// </param>
    /// <param name="initVector">
    /// Initialization vector (or IV). This value is required to encrypt the
    /// first block of plaintext data. For RijndaelManaged class IV must be 
    /// exactly 16 ASCII characters long.
    /// </param>
    /// <param name="keySize">
    /// Size of encryption key in bits. Allowed values are: 128, 192, and 256. 
    /// Longer keys are more secure than shorter keys.
    /// </param>
    /// <returns>
    /// Encrypted value formatted as a base64-encoded string.
    /// </returns>
    public static string Encrypt(string   plainText,
                                 string   passPhrase,
                                 string   saltValue,
                                 string   hashAlgorithm,
                                 int      passwordIterations,
                                 string   initVector,
                                 int      keySize)
    {
        // Convert strings into byte arrays.
        // Let us assume that strings only contain ASCII codes.
        // If strings include Unicode characters, use Unicode, UTF7, or UTF8 
        // encoding.
        byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
        byte[] saltValueBytes  = Encoding.ASCII.GetBytes(saltValue);
        
        // Convert our plaintext into a byte array.
        // Let us assume that plaintext contains UTF8-encoded characters.
        byte[] plainTextBytes  = Encoding.UTF8.GetBytes(plainText);
        
        // First, we must create a password, from which the key will be derived.
        // This password will be generated from the specified passphrase and 
        // salt value. The password will be created using the specified hash 
        // algorithm. Password creation can be done in several iterations.
        PasswordDeriveBytes password = new PasswordDeriveBytes(
                                                        passPhrase, 
                                                        saltValueBytes, 
                                                        hashAlgorithm, 
                                                        passwordIterations);
        
        // Use the password to generate pseudo-random bytes for the encryption
        // key. Specify the size of the key in bytes (instead of bits).
        byte[] keyBytes = password.GetBytes(keySize / 8);
        
        // Create uninitialized Rijndael encryption object.
        RijndaelManaged symmetricKey = new RijndaelManaged();
        
        // It is reasonable to set encryption mode to Cipher Block Chaining
        // (CBC). Use default options for other symmetric key parameters.
        symmetricKey.Mode = CipherMode.CBC;        
        
        // Generate encryptor from the existing key bytes and initialization 
        // vector. Key size will be defined based on the number of the key 
        // bytes.
        ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
                                                         keyBytes, 
                                                         initVectorBytes);
        
        // Define memory stream which will be used to hold encrypted data.
        MemoryStream memoryStream = new MemoryStream();        
                
        // Define cryptographic stream (always use Write mode for encryption).
        CryptoStream cryptoStream = new CryptoStream(memoryStream, 
                                                     encryptor,
                                                     CryptoStreamMode.Write);
        // Start encrypting.
        cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                
        // Finish encrypting.
        cryptoStream.FlushFinalBlock();

        // Convert our encrypted data from a memory stream into a byte array.
        byte[] cipherTextBytes = memoryStream.ToArray();
                
        // Close both streams.
        memoryStream.Close();
        cryptoStream.Close();
        
        // Convert encrypted data into a base64-encoded string.
        string cipherText = Convert.ToBase64String(cipherTextBytes);
        
        // Return encrypted string.
        return cipherText;
    }
    
    /// <summary>
    /// Decrypts specified ciphertext using Rijndael symmetric key algorithm.
    /// </summary>
    /// <param name="cipherText">
    /// Base64-formatted ciphertext value.
    /// </param>
    /// <param name="passPhrase">
    /// Passphrase from which a pseudo-random password will be derived. The
    /// derived password will be used to generate the encryption key.
    /// Passphrase can be any string. In this example we assume that this
    /// passphrase is an ASCII string.
    /// </param>
    /// <param name="saltValue">
    /// Salt value used along with passphrase to generate password. Salt can
    /// be any string. In this example we assume that salt is an ASCII string.
    /// </param>
    /// <param name="hashAlgorithm">
    /// Hash algorithm used to generate password. Allowed values are: "MD5" and
    /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
    /// </param>
    /// <param name="passwordIterations">
    /// Number of iterations used to generate password. One or two iterations
    /// should be enough.
    /// </param>
    /// <param name="initVector">
    /// Initialization vector (or IV). This value is required to encrypt the
    /// first block of plaintext data. For RijndaelManaged class IV must be
    /// exactly 16 ASCII characters long.
    /// </param>
    /// <param name="keySize">
    /// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
    /// Longer keys are more secure than shorter keys.
    /// </param>
    /// <returns>
    /// Decrypted string value.
    /// </returns>
    /// <remarks>
    /// Most of the logic in this function is similar to the Encrypt
    /// logic. In order for decryption to work, all parameters of this function
    /// - except cipherText value - must match the corresponding parameters of
    /// the Encrypt function which was called to generate the
    /// ciphertext.
    /// </remarks>
    public static string Decrypt(string   cipherText,
                                 string   passPhrase,
                                 string   saltValue,
                                 string   hashAlgorithm,
                                 int      passwordIterations,
                                 string   initVector,
                                 int      keySize)
    {
        // Convert strings defining encryption key characteristics into byte
        // arrays. Let us assume that strings only contain ASCII codes.
        // If strings include Unicode characters, use Unicode, UTF7, or UTF8
        // encoding.
        byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
        byte[] saltValueBytes  = Encoding.ASCII.GetBytes(saltValue);
        
        // Convert our ciphertext into a byte array.
        byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
        
        // First, we must create a password, from which the key will be 
        // derived. This password will be generated from the specified 
        // passphrase and salt value. The password will be created using
        // the specified hash algorithm. Password creation can be done in
        // several iterations.
        PasswordDeriveBytes password = new PasswordDeriveBytes(
                                                        passPhrase, 
                                                        saltValueBytes, 
                                                        hashAlgorithm, 
                                                        passwordIterations);
        
        // Use the password to generate pseudo-random bytes for the encryption
        // key. Specify the size of the key in bytes (instead of bits).
        byte[] keyBytes = password.GetBytes(keySize / 8);
        
        // Create uninitialized Rijndael encryption object.
        RijndaelManaged    symmetricKey = new RijndaelManaged();
        
        // It is reasonable to set encryption mode to Cipher Block Chaining
        // (CBC). Use default options for other symmetric key parameters.
        symmetricKey.Mode = CipherMode.CBC;
        
        // Generate decryptor from the existing key bytes and initialization 
        // vector. Key size will be defined based on the number of the key 
        // bytes.
        ICryptoTransform decryptor = symmetricKey.CreateDecryptor(
                                                         keyBytes, 
                                                         initVectorBytes);
        
        // Define memory stream which will be used to hold encrypted data.
        MemoryStream  memoryStream = new MemoryStream(cipherTextBytes);
                
        // Define cryptographic stream (always use Read mode for encryption).
        CryptoStream  cryptoStream = new CryptoStream(memoryStream, 
                                                      decryptor,
                                                      CryptoStreamMode.Read);

        // Since at this point we don't know what the size of decrypted data
        // will be, allocate the buffer long enough to hold ciphertext;
        // plaintext is never longer than ciphertext.
        byte[] plainTextBytes = new byte[cipherTextBytes.Length];
        
        // Start decrypting.
        int decryptedByteCount = cryptoStream.Read(plainTextBytes, 
                                                   0, 
                                                   plainTextBytes.Length);
                
        // Close both streams.
        memoryStream.Close();
        cryptoStream.Close();
        
        // Convert decrypted data into a string. 
        // Let us assume that the original plaintext string was UTF8-encoded.
        string plainText = Encoding.UTF8.GetString(plainTextBytes, 
                                                   0, 
                                                   decryptedByteCount);
        
        // Return decrypted string.   
        return plainText;
    }
}

/// <summary>
/// Illustrates the use of RijndaelSimple class to encrypt and decrypt data.
/// </summary>
public class RijndaelSimpleTest
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
        string   plainText          = "Hello, World!";    // original plaintext
        
        string   passPhrase         = "Pas5pr@se";        // can be any string
        string   saltValue          = "s@1tValue";        // can be any string
        string   hashAlgorithm      = "SHA1";             // can be "MD5"
        int      passwordIterations = 2;                  // can be any number
        string   initVector         = "@1B2c3D4e5F6g7H8"; // must be 16 bytes
        int      keySize            = 256;                // can be 192 or 128
        
        Console.WriteLine(String.Format("Plaintext : {0}", plainText));

        string  cipherText = RijndaelSimple.Encrypt(plainText,
                                                    passPhrase,
                                                    saltValue,
                                                    hashAlgorithm,
                                                    passwordIterations,
                                                    initVector,
                                                    keySize);

        Console.WriteLine(String.Format("Encrypted : {0}", cipherText));
        
        plainText          = RijndaelSimple.Decrypt(cipherText,
                                                    passPhrase,
                                                    saltValue,
                                                    hashAlgorithm,
                                                    passwordIterations,
                                                    initVector,
                                                    keySize);

        Console.WriteLine(String.Format("Decrypted : {0}", plainText));
    }
}
//
// END OF FILE
///////////////////////////////////////////////////////////////////////////////

Wednesday, February 24, 2010

Google Tasks - Bookmarklet

Here is a bookmarklet that opens Google Tasks in its own little window:

javascript:newwindow=window.open('http://mail.google.com/tasks/ig','','resizable=1,toolbar=0,location=0,status=0,menubar=0,scrollbars=1,width=400,height=600');newwindow.focus();

Just create a bookmark, open its properties and paste the above code into the address field. Move the bookmark to your toolbar for easy access.

Tuesday, February 23, 2010

DotNetNuke Zero Day Vulnerability (semi-colon bug)

There is a major security loop hole in DotNetNuke versions 4.9.2 and below where DNN will allow an unauthorized user to upload almost any file onto the server. This loop hole combined with the IIS 5/6 zero day multiple extension exploit can allow a hacker complete access to your website.So if you are a DNN version that is not 4.9.4 and up – read on as this is huge hole in your website.
The DNN Issue:
If you browse to the following sub-folder on your DNN site “Providers/HtmlEditorProviders/Fck/fcklinkgallery.aspx”, you will see a page that looks like this:
 image
The above page on its own is not too bad. But if you now paste the following javascript code into the address bar and hit enter: “javascript:__doPostBack('ctlURL$cmdUpload','')” you will see the following browse dialog which will allow you to upload almost any file onto the website (restricted to the list of files allowed by FCKEditor – typically images, documents, etc).
image
The above hack will typically lead to hackers dropping small txt files that have some kind of a notice saying that your website has been hacked!
image
It is hard to do anything substantial with this hack alone.
But wait there is more…..
The IIS Issue:
On December 25th of 2009, an “Ethical” hacker found a vulnerability in IIS 5 and IIS 6 called the “semi-colon” bug or the “multiple extensions IIS/ASP bug”. Read More.
The semi-colon bug allows any file that has .asp in the file name to execute as an ASP file. This bug occurs in all versions of IIS 6 and prior. This means that a file named “innocusFile.asp;.jpg” will be executed like an ASP file.
The big scary picture:
The 2 bugs on their own were bad, but it still would be hard for anything bad to happen. But together – they open up a can of worms that is going to make everyone in your organization pulling every fire alarm in the building. Here is the big picture:
1. Hacker fabricates an ASP file that uses COM objects such as the FileSystemObject to get complete access to your computer.
2. Hacker names the asp file as “myHack.asp;.jpg”.
3. Hacker navigates to the “Providers/HtmlEditorProviders/Fck/fcklinkgallery.aspx” file in his browser and uses the DNN loop hole to upload his myHack.asp;.jpg file. DNN complies because it thinks it is a simple jpg file. This is because DNN looks only at the last extension it finds in a file name.
4. The file uploads to the DNN website to the folder (WITHHELD – to protect unprotected DNN sites).
5. The hacker browses to the file that he uploaded. The file is delivered to the ASP processing engine by IIS and a page that opens up the entire computer to the hacker is displayed. This is because IIS has been coded such that it recognizes a file type based on its extension even if the extension is not the last part of the file name!!
6. The hacker uses his ASP page to get full control of your website (and I mean full control – all disk drives, connection strings, databases, registy, etc.). Nothing is safe after this.
Here is a sample ASP file called the “Smart Shell”, that basically shows the capabilities that an hacker can get over your website: (This kind of an ASP file is also called the 3fexe ASP hack).
image
How to mitigate:
Because there is no known fix, there are only ways to mitigate this attack (and hence it is a zero-day hack).
1. Rename the fcklinkgallery.aspx file
As fcklinkgallery.aspx is the entry point for this hack attack, the first thing to do is to rename this file. I suggest using a random file name – like a guid. After you rename the file, you will need to update the “LinksGalleryPath” setting in your config file. This will be found in the <dotnetnuke><htmlEditor><providers><add name="FckHtmlEditorProvider"> section. Just look for “LinksGalleryPath” and update the value to the newly named file name.
If the hacker cannot browse to the fcklinkgallery.aspx file, he will not be able to upload a ASP file onto your DNN site.
(Update: 03-30-2010) please note: Gabe has included an extra step that needs to be taken to get the link editor to work after renaming it. Please see the comments below. Basically you need to also rename the  "\Providers\HtmlEditorProviders\Fck\App_LocalResources\fcklinkgallery.aspx.resx" to match the renamed fckLinkGallery file.)

2. Remove Execute permission on the Portals folder of your DNN site.
The sub-folder “Portals” in your DNN site typically does not need to be able to run ASP files or any other files. So remove “Execute” permissions on that folder.
Open up IIS.
Expand the website node for your DNN site.
Select the Portals node in the explorer view on the left.
Right click on the Portals node and open the Properties dialog.
Chose the Directory Node.
Set Execute Permissions to “None”.

3. Remove access to FileSystemObject.
This falls into the excessively precautious as it is not really required for you to do. An important note: Do not do this if you know that you have some ASP apps on your site and if those ASP apps use FileSystemObject – you might end up hosing those apps.
There are 2 ways to do this: Remove access to this COM object from the security principal used to run your IIS website (typically ASPNET) or to completely unregister the dll.
1. Registry access:
Open registry editor.
Browse to “HKEY_CLASSES_ROOT\Scripting.FileSystemObject”, right click and under permissions deny access to the ASPNET user.
2. Completely disable FileSystemObject
Run regsvr32 scrrun.dll .u in the C:\windows\System32 folder.
Remember – step 3 is really not required to be done.

The only Fix:

The only “true” fix is to upgrade to IIS 7 or higher and a DNN version of 4.9.4 or higher.
Notes:
Securing IIS 6.0:
http://technet.microsoft.com/en-us/library/cc875829.aspx
One way hacking (which is what the above type of hack is known as):
http://www.net-square.com/papers/one_way/one_way.html
Restricting information available to anonymous users:
http://support.microsoft.com/kb/143474
DNN LinkGallery Remote File Upload without Extension:
http://securityreason.com/exploitalert/6234
DNN Failure to revalidate file and folder permissions correctly for uploads:
http://www.dotnetnuke.com/News/SecurityPolicy/SecurityBulletinno17/tabid/1162/Default.aspx
IIS Security Vulnerability and DNN
http://www.dotnetnuke.com/Community/Forums/tabid/795/forumid/108/postid/347394/scope/posts/Default.aspx

SQL Server and External Connector Licenses

If you have a web-application that uses a SQL Server database then you might have to buy an external connector license (this I did not know before today – luckily we have a licensing guy in our org.)

From http://www.microsoft.com/licensing/about-licensing/client-access-license.aspx:

External Connector Licensing:

An external user is a person who is not an employee or similar personnel of the company or its affiliates, and is not someone to whom you provide hosted services. An EC license assigned to a server permits access by any number of external users, as long as that access is for the benefit of the licensee and not the external user.

Anyways, the only time you wont need an external connector license for your SQL Server database is when your installation is licensed by the processor.

Per Processor Licensing

Under the Per Processor model, you acquire a Processor License for each processor in the server on which the software is running. A Processor License includes access for an unlimited number of users to connect from either inside the local area network (LAN) or wide area network (WAN), or outside the firewall (via the Internet). You do not need to purchase additional server licenses, CALs, or Internet Connector Licenses.

Monday, February 22, 2010

Response.Redirect cannot be called in a Page callback

If you are getting the “Response.Redirect cannot be called in a Page callback” then you are most probably using AJAX and you are using a Response.Redirect (or Server.Transfer) in an event that was fired from within an AJAX panel.

The reason this does not work is that there is only a partial post-back that occurs with controls that are within an AJAX panel and you cannot perform a Redirect from within a partial post-back.

Fixes:

1. Dont do a redirect in an event that is fired due to a partial post-back!

2. In the event, instead of doing a redirect, register a javascript method that will perform the redirect from the client’s browser. eg:

string script = string.Format("document.location.href = '{0}');", "pageToRedirectTo.aspx");
ScriptManager.RegisterClientScriptBlock(Page, typeof(Page), "redirect", script, true);

Saturday, February 20, 2010

MousePath – create your own art

Came across this very cool app that tracks your mouse and draws out lines on a large canvas. The app is called MousePath and was created by Anatoliy Zenkov.

MousePath is a Java app and can be downloaded for the PC (dl.dropbox.com/u/684632/mousepath.exe.zip) and Mac(dl.dropbox.com/u/684632/mousepath.jar)

You run the app and leave it in its maximized state and then go about doing your daily work. And when you are happy with the art created just hit the S button and it will create a file in the same folder where the app is running.

Here is my mousepath art created after 30 minutes:

mousePath

Friday, February 19, 2010

BBC Redesign

Here is a post on how the BBC is redesigning their new website. I found it an interesting study in design and how through their project was (setting guidelines on underlying grids, color palettes, embedding of audio/video, etc).

Also as some one who is completely bereft of the ability to choose good colors that go well with each other, there are palettes on the page that I could use on my web-pages (as well as other design pointers).

http://www.bbc.co.uk/blogs/bbcinternet/2010/02/a_new_global_visual_language_f.html

3-GVL2-Grid

Keeping Employees Motivated

From a Harvard Business School article:

First step: stop demotivating employees

According to the author there are just three important factors that matter most when it comes to keeping employees motivated:

  • Equity: To be respected and to be treated fairly in areas such as pay, benefits, and job security.
  • Achievement: To be proud of one's job, accomplishments, and employer.
  • Camaraderie: To have good, productive relationships with fellow employees.

Interestingly, the author found that if one of the above factors is missing, then they cannot be substituted with another factor (for e.g: higher pay).

And here are the main things the author says managers can do in different areas:

  • Achievement related
    • Instill an inspiring purpose
    • Provide recognition
    • Be an expediter for your employees
    • Coach your employees for improvement
  • Equity related
    • Communicate fully
    • Face up to poor performance
  • Camaraderie related
    • Promote teamwork
  • All three areas (Achievement, Equity and Camaraderie)
    • Listen and involve

Read the entire article as it elaborates on the above listed points.

http://hbswk.hbs.edu/archive/5289.html

Wednesday, February 17, 2010

Artisteer – Create templates for some common content systems

I have written many times on this blog that the one skill that I lack is that of an artist. Colors, layout, etc are hard for me to just create. But when I see good design, I know it. It just appeals to me. If I have to work with a good designer, then I can come up with some cool UIs – but a good designer is a luxury that isnt always available on all the projects that we work on. This is especially true for personal projects.

Today I came across a tool called Artisteer. It looks very promising as a template creation engine, that makes it extremely easy to create design templates for CMSs like DotNetNuke, Blogger, etc.

I plan on writing more about my experience with Artisteer.

Today I tested it out with Blogger and I realized that I needed to backout the change. While exporting a template, Artisteer displayed a message about saving a backup of the existing template. But when the time came to revert back to the old design, I could not find it on my machine. Here is where you can find it:

Windows 7: C:\Users\<USER_NAME>\AppData\Roaming\Artisteer\Artisteer2\Library\BloggerBackup

Windows Vista: C:\Documents and Settings\<USER_NAME>\Application Data\Artisteer\Artisteer2\Library\BloggerBackup

Disclosure: I requested a demo license from Artisteer creators to test out the capabilities of the tool when it comes to Blogger blogs and DotNetNuke. The above instruction, as well as any others that I create related to Artisteer, will be based on my testing with a Artisteer version activated by a free license key provided by the developers of the app.

Recycled Material Art

Recycled material/art I came across

DNN Redirect Loop

I was setting up a local dev edition of our DNN site and I went through the usual cycle:

1. Copy site to local machine

2. Set the permissions on the folder

3. Create a website in IIS

4. Copy the database to the local SQLServer Express instance

5. Update the Portal Alias table to point to the localhost

6. Update web.config’s connection strings and SiteSQLServer settings as well as the “SecureDomains”, “RedirectUrl’, and “DisplayServer” to point to the localhost.

7. Test

Hmmph!

The homepage was ending up in an infinite redirect loop (IE does not complain and just keeps on going in the loop. Chrome is smarter about this and complains and stops with an error page).

Weird thing was that I could hit a page alright if I had the correct tabid. But I could not just go “http://localhost/”

I checked the usual suspects – the PortalAlias table and also made sure that none of the entries ended with a “/” – all that was fine.

Finally found out the issue was occuring because the RedirectUrl setting in the web.config file had a trailing “/” (http://localhost/"). DNN does not like that!

Comcast XFinity

Heard about Comcast’s XFinity upgrade today (it isnt yet available in my neck of the woods in Denver), but the features look interesting:

From Xfinity.com:

  • 50Mbps downloads today, increasing to 100+ Mbps and even faster in the future
  • 100+ HD channels, 5,000+ HD choices, and the best HD picture quality available
  • 50 to 70 multi-cultural channels
  • Approaching 20,000+ Video On Demand titles
  • Fancast XFINITY TV, with 19,000+ movies, top shows, and other content available online, at home or on the go
  • New cross-platform and mobile features like: remote DVR, Universal Caller ID, an interactive home telephone, apps for iPhones and the ability to use a remote control to order products and services while watching TV

Comcast’s service has overall been good. My only problem with them has been the price that they think their customers are willing to pay. I am seriously considering cutting out cable the next time I have to renew my services at a higher fee.

Tuesday, February 16, 2010

Denver DNN User Group Meeting

The next DNN user group meeting will be held at the City and County of Denver’s Webb Municipal building…. more info:
http://denver.dnnug.com/news/itemId/40/February-2010-Meeting-2232010--Chris-Hammond-.aspx

Thursday, February 11, 2010

Reading CSV files in .NET

I have typically used a “StreamReader” to read through text files when I had to parse out comma separated variables. This normally meant that I had to do a lot of the lifting of reading values, parsing them and handling exceptions. And most often the case was that I was reading the data into a DataSet which could then be easily displayed in a UI

Today I was shown a much easier way to do the above using the Excel engine by Joe Harker. It uses an ODBC driver to read a CSV file just like you would read in data from any database. The trick is to use the correct connection string. Here is a sample connection string:
”Provider=\"Microsoft.Jet.OLEDB.4.0\";Data Source=\"{0}\";Extended Properties=\"Excel 8.0; HDR=Yes; IMEX=0\"";

[Important Update: 02-12-2010]

There is a limitation with the JET engine – it can be used to read in only 65,535 rows of data and 255 columns of data. (not sure if this limit is different on 64 bit machines).

For more information:

Text File Driver Programming Considerations

Using OleDb to Import Text Files

Customizing how data is read using a schema.ini file

OLE DB Programmers Guide – Jet Provider

OLE DB Tutorial – C#

JET SQL

Color Theory

As a software developer I have always found myself deficient in the area of colors. I can make a simple interface with just black and white colors or I can apply predetermined colors part of a template/scheme to a page to make it pretty. But what I cannot do is to select colors on my own to make a page look aesthetic and pleasing. So I am always on the look out for tutorials/documents that help me in this area:

Here is a collection from Smashing Magazine:

Color Theory for Designers, Part 1: The Meaning of Color

Color Theory For Designers, Part 2: Understanding Concepts And Terminology

Color Theory for Designer, Part 3: Creating Your Own Color Palettes

Monday, February 08, 2010

Chrome Extension for checking Google Accounts

Best Chrome Extension for checking on the status of your Google Accounts: One Number

image

ADO.Net Entity Data Model – beginner mistakes

Are you getting the “Unable to update the EntitySet ‘xxxx’ because it has a DefiningQuery and no <InsertFunction>”

Check to make sure your table has a primary key – I think the reason that you get this error is that because your table does not have a primary key, EF looks at your table like a view that is not directly updatable and needs special logic (either through .Net code or a stored procedure) to update the table.

Set the primary key, delete the EF model and then re-add it (just refreshing the model didnt do it for me). And you should be back in business.

Sunday, February 07, 2010

Siri – The personal assistant for the iPhone

A very cool iPhone app that uses voice recognition to hail taxis, suggest restaurants and even tell you where to go for a haircut. Siri

I really like the intelligence built into the search: Like when I said “I need a hair cut”, it automatically figured out I wanted a hair cutting salon and when I said “Chinese take out”, it automatically looked up Yelp for Chinese restaurants that deliver!

Also available for other phones – like the Blackberry

The Agile Program Manager’s Cheat Sheet

From Sara Ford’s blog:

Good information on what goes into planning for an Agile iteration from someone who talks the talks and walks the walk.

How Agile Works

Release Overview Diagram

Each number represents an iteration, which is a week of work. I1, I2, and I3 are the development iterations. The majority of a Program Manager’s time is spent in the pre-I1 iterations, named –3, –2, and –1.

The Epic Story – This is what goes on a sticky note on the whiteboard. For example, “Ratings and Reviews for Project releases” is an epic story with the following stories associated with it.

  1. Rate Release
  2. Display ratings and reviews on release page
  3. Display ratings and reviews on project homepage
  4. Move release metadata to new location  // also a UX improvement Epic story
  5. Releases sorted by date with release ratings  // also a UX improvement Epic story

Pre-Iteration Planning Meeting (IPM) Planning (about 10 weeks out from deployment date)

These are the series of Program Manager tasks that need to be completed in this order:

  1. Epic + Proposed Stories are written
  2. Wireframes are designed
  3. Review wireframes with team
  4. Rewrite stories based on wireframes
  5. Prioritize what gets done first in terms of dependences
    1. Think about how non-dependencies can be done later or separately
  6. Talk to developers for high-level estimates
    1. These "stories” should be in terms of < 5 days of work
  7. Talk to test team about acceptance tests

Product Backlog

  • Story must be ready at I1 (the first iteration of development work). This must be actionable work, meaning the developer can grab the story (and wireframe if appropriate) and start coding immediately.
  • Story entered as feature in product backlog
  • Have about 9-10 weeks of work in Product Backlog at all times

Iteration Planning Meeting (IPM)

  • Program Manager –> Developer translation occurs with each story
  • Developer breaks story down into their language and into their own tasks. (again, this is where the dev is in charge of the how and the PM is in charge of the what).
  • The team as a collective aims for how much work they can do in that one week. Everything beyond that is put back into the backlog for re-priorization by the Program Manager for the next IPM

Boilerplate HTTPHandler

I have a couple of aspx pages (that I inherited from a project) that are never really used to render HTML content to an end user and instead are used to receive a HTTP post message and process the contents. Granted that I could use a web-service to process the messages being sent – but that would involve changing the clients that send the post messages and those are out of my control.

Today I came across the IHttpHandler and this will work perfectly for me:
1. Clients can continue sending their post messages
2. I can re-architect the pages to be HttpHandlers and save on a lot of extra handling that the normal aspx page would have to do.

IHttpHandler defines the contract that ASP.NET implements to synchronously process HTTP Web requests using custom HTTP handlers

And here is a base class HttpHandler by Phil Hack that I think will be useful for just such a project: http://haacked.com/archive/2005/03/17/AnAbstractBoilerplateHttpHandler.aspx

Phil Hacks HttpHandler base class is based on a Scott Hanselman base-class: http://www.hanselman.com/blog/PermaLink,guid,5c59d662-b250-4eb2-96e4-f274295bd52e.aspx

More Info: Code-behind for HTTPHandlers: http://aspnetresources.com/blog/httphandler_code_behind.aspx

Wednesday, February 03, 2010

JQuery/JavaScript Demo – a Photoshoot plugin

Bet you didnt think Javascript could do this: Demo

And here is how they did it: http://tutorialzine.com/2010/02/photo-shoot-css-jquery/

Very Cool!

Allowing a SQL Server user to execute stored procedures

There doesnt seem to be a straightforward way to do this using the GUI in SQL Server Management Studio.

I like managing users using roles and the following method is an easy way to provide a user the permission to execute all stored procedures in that database.

You create a role called db_executor and grant the role Execute priviledges. You then assign the user that needs the ability to execute stored procs to the db_executor role.

CREATE ROLE db_executor
GRANT EXECUTE TO db_executor

I am not a DBA – so I am not sure if this is not a good practice (because you end up giving execute permissions on all stored procs to all users assigned to that role). Leave a comment if you know otherwise.

Attaching a SQL Server database file (mdf) without an associated log (ldf) file

If you try and attach a mdf file that does not have an associated ldf file in SQL Server Management Studio, SSMS will throw an error. The simplest way around it is – click on the ldf file location in the dialog and click Remove. SSMS will then attach the MDF file and create the associated LDF file for you.

Tuesday, February 02, 2010

MSDASQL for 64 bit windows

Most articles that I found about MSDASQL for 64 bit Windows said that MSDASQL support was not going to be available.

This was a big let down for my team, as we had this brand spanking new 64 bit web-server and we had some old ASP apps that needed to be hosted on it. The reason this was a let down was that these old ASP apps were using a MSDASQL data provider with a MSDataShape provider and the app just would not run.

After some more debugging we found that a desktop app that used the same connection string would work if it was built as a 32 bit app but not as a 64 bit app. This meant that the server had 32 bit versions of the ODBC drivers needed for MSDASQL/MSDataShape, but not the 64 bit versions. (The 64 bit app would fail with the “Class not registered” error – the same error I was getting when the ASP app was running).

The reason this was a let down was that, without 64 bit OleDb ODBC drivers, we would have to run IIS in 32 bit isolation mode (we have IIS6 which supports an either or as far as running in 32 bit or 64 bit mode is concerned – I think this is not the case with IIS7). As we were not going to be able to move to IIS 7, it looked as though we were going to have to run IIS in 32 bit isolation mode – which means that I cannot load any 64 bit dlls – what good would the 64 bit environment be then?

Fortunately I found the following Microsoft Download page, where version 2.82.4250.0 of the OLEDB Provider for ODBC can be downloaded, which provides support for 64 bit Windows 2003.

http://www.microsoft.com/downloads/details.aspx?FamilyID=000364db-5e8b-44a8-b9be-ca44d18b059b&displaylang=en

After installing and rerunning the application – the old ASP app began working in the new environment. Hallelujah!

Testing your WCF service

If your WCF service has a BasicHttpBinding endpoint – then you can use SoapUI for testing.

If you need to test a WSHttpBinding endpoint – then I found that SoapUI had a problem creating the correct requests. Instead you can use the WCF Test Client that comes with VS 2008 and can be found at: "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\WcfTestClient.exe"

Monday, February 01, 2010

Javascript – a quick and robust check for NotANumber (NAN)

Javascript provides the NaN property that returns a value that represents NotANumber (NAN).
eg: Number.NaN

But you cannot use the following check to test for a variable containing a NaN:
(someValue == Number.NaN)

The reason is because Number.NaN != Number.NaN by definition of the IEEE standards.

This inequality can be used to your advantage by using the following check:
(someValue != someValue)
The only time the above check will fail is that if someValue contains a NaN value.

Or you can use the global function isNaN(someValue).

note: the (someValue != someValue) is a check that works in many other languages (eg: c, c++, SQL, etc) which is why it is a useful idea to brush into the recesses of your memory.

Looking for a new website host

I am looking for a website host. They should support:

  • ASP.Net (2.x,3.x and 4.x when it comes out)
  • Silverlight
  • SQL Server 2008 (at a minimum Express edition)
  • Should be cheap ($5 a month? – I was spoiled – for the last 2 years I had all of the above for free – courtesy of the Denver Dot Net Developer Group and www.Verio.com)

Any suggestions?