<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://weblogs.asp.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>ScottGu's Blog : Security</title><link>http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx</link><description>Tags: Security</description><dc:language>en</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><item><title>Tip/Trick: Enabling SSL on IIS 7.0 Using Self-Signed Certificates</title><link>http://weblogs.asp.net/scottgu/archive/2007/04/06/tip-trick-enabling-ssl-on-iis7-using-self-signed-certificates.aspx</link><pubDate>Fri, 06 Apr 2007 07:31:31 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:2186474</guid><dc:creator>ScottGu</dc:creator><slash:comments>18</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=2186474</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2007/04/06/tip-trick-enabling-ssl-on-iis7-using-self-signed-certificates.aspx#comments</comments><description>&lt;font face="arial" size="2"&gt; &lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Transport_Layer_Security" target="_blank"&gt;SSL&lt;/a&gt; enables browsers to communicate with a web-server over a secure channel that prevents eavesdropping, tampering and message forgery.&amp;nbsp;&amp;nbsp;You should&amp;nbsp;always use SSL for login pages where users are entering usernames/passwords, as well as for all other sensitive pages on sites (for example: account pages that show financial or personal&amp;nbsp;information).&amp;nbsp;&lt;/p&gt; &lt;p&gt;Configuring SSL on Windows with previous versions of IIS has been a pain.&amp;nbsp; Figuring out how to install and manage a certificate, and then associate it with a web-site, is something I bet most web developers don't know how to enable.&lt;/p&gt; &lt;p&gt;The good news is that IIS 7.0 makes it radically easier to configure and enable SSL.&amp;nbsp; IIS 7.0 also now has built-in support for creating "Self Signed Certificates" that enable you to easily create test/personal certificates that you can use to quickly SSL enable a site for development or test purposes.&amp;nbsp; &lt;/p&gt; &lt;p&gt;Using IIS 7.0 you can SSL enable an existing web site in under 30 seconds.&amp;nbsp; The below tutorial demonstrates how to-do this.&lt;/p&gt; &lt;h5&gt;&lt;strong&gt;&lt;u&gt;Step 1: Create a New Web Site&lt;/u&gt;&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;We'll start by creating a new web-site using the new IIS 7.0 admin tool.&amp;nbsp; This admin tool is a complete re-write of the previous IIS admin tool (and was written entirely in managed code using Windows Forms), and provides a more logical organization of web features.&amp;nbsp; It provides a GUI admin experience for all ASP.NET and IIS settings:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;img src="http://www.scottgu.com/blogposts/ssl/step0.jpg"&gt; &lt;/p&gt; &lt;p&gt;To create a new site on the box, right click on the "Web Sites" node in the left hand tree-view pane and choose the "Add Web Site" context menu option.&amp;nbsp; Enter the appropriate details to create a new web-site:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/ssl/step1.jpg"&gt; &lt;/p&gt; &lt;p&gt;One nice feature of IIS7 on Windows Vista is that you can now have an unlimited number of sites on a box (previous versions of IIS on Windows Client only allowed 1 site).&amp;nbsp; The 10 simultaneous request limitation on Windows Client versions of IIS also no longer exists with IIS 7.0.&lt;/p&gt; &lt;p&gt;Once we've completed the above steps, we will now have a brand new site running on our IIS web-server.&lt;/p&gt; &lt;h5&gt;&lt;strong&gt;&lt;u&gt;Step 2: Create a new Self Signed Certificate&lt;/u&gt;&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;Before binding SSL rules to our new site, we need to first import and setup&amp;nbsp;a security certificate to use with the SSL binding.&amp;nbsp; &lt;/p&gt; &lt;p&gt;Certificates are managed in IIS 7.0 by clicking the root machine node in the left-hand tree-view explorer, and then selecting the "Server Certificates" icon in the feature pane on the right:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/ssl/step3.jpg"&gt; &lt;/p&gt; &lt;p&gt;This will then list all certificates registered on the machine, and allow you to optionally import and/or create new ones.&lt;/p&gt; &lt;p&gt;I could optionally go to a certificate authority like Verisign and purchase a certificate to import using this admin UI.&amp;nbsp; Alternatively, I can create a "self-signed certificate" which is a test certificate that I can use during the development and testing of my site.&amp;nbsp; To-do this, click the "Create Self-Signed Certificate" link on the right-hand side of the admin tool:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/ssl/step4.jpg"&gt; &lt;/p&gt; &lt;p&gt;Enter a name to use for the certificate (for example: "test") and hit ok.&amp;nbsp; IIS7 will then automatically create a new self-signed crypto certificate for you and register it on the machine:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/ssl/step5.jpg"&gt; &lt;/p&gt; &lt;h5&gt;&lt;strong&gt;&lt;u&gt;Step 3: Enable HTTPS Bindings for our New Site&lt;/u&gt;&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;To SSL enable the web-site we created earlier, select the web-site node in the left-hand tree-view, and the click the "Bindings" link in its "actions" pane on the right-hand side of the screen:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/ssl/step6.jpg"&gt; &lt;/p&gt; &lt;p&gt;This will then bring up a dialog that lists all of the binding rules that direct traffic to this site (meaning the host-header/IP address/port combinations for the site):&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/ssl/step7.jpg"&gt; &lt;/p&gt; &lt;p&gt;To enable SSL for the site, we'll want to click the "Add" button.&amp;nbsp;This will&amp;nbsp;bring up an "add binding" dialog that we can&amp;nbsp;use to add HTTPS protocol support.&amp;nbsp; We can select the self-signed certificate we created earlier from the SSL certificate dropdownlist in the dialog, and in doing so&amp;nbsp;indicate that we want to use that certificate when encrypting content over SSL:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/ssl/step8.jpg"&gt; &lt;/p&gt; &lt;p&gt;Click ok, and we now have SSL enabled for our site:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/ssl/step9.jpg"&gt; &lt;/p&gt; &lt;h5&gt;&lt;strong&gt;&lt;u&gt;Step 4: Test out the Site&lt;/u&gt;&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;Add a "default.aspx" page to the site, and then try and hit it with the browser by typing &lt;a href="https://localhost/default.aspx"&gt;https://localhost/default.aspx&lt;/a&gt;&amp;nbsp;(note the usage of "https" instead of "http" to indicate that you want to connect over SSL). &lt;/p&gt; &lt;p&gt;If you are using IE7, you'll likely see this anti-phishing error message kick in&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/ssl/step10.jpg"&gt; &lt;/p&gt; &lt;p&gt;Don't panic if this happens - it is just IE being helpful by suggesting that a self-signed certificate on your local machine looks suspicious. Click the "Continue to this website" link to bypass this security warning and proceed to&amp;nbsp;the site.&amp;nbsp; You'll find that your&amp;nbsp;default.aspx page is now running protected via SSL:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/ssl/step11.jpg"&gt; &lt;/p&gt; &lt;p&gt;You are all done. :-)&lt;/p&gt; &lt;h5&gt;&lt;strong&gt;&lt;u&gt;Appendix: A Few Last SSL Notes&lt;/u&gt;&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;A few last SSL related notes:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;The IIS 7.0 admin tool has an "SSL Settings" node that you can select for each site, directory or file that allows you to control whether that particular resource (and by default its children) requires an SSL request in order to execute.&amp;nbsp; This is useful for pages like a login.aspx page, where you want to guarantee that users can only enter their credentials when they are posting via an encrypted channel. If you configure the login.aspx page to require SSL, IIS 7.0 will block browsers from accessing it unless they are doing so over SSL.&lt;/li&gt;&lt;/ul&gt; &lt;ul&gt; &lt;li&gt;Within an ASP.NET page or handler, you can programmatically check whether the current request is using SSL by checking the Request.IsSecure property (it will return "true" if the incoming browser request is over SSL). &lt;/li&gt;&lt;/ul&gt; &lt;ul&gt; &lt;li&gt;You can set the "requireSSL" attribute on the &amp;lt;forms&amp;gt; configuration section within web.config files to have ASP.NET's forms-authentication system ensure that forms-authentication cookies are only set and used on SSL enabled pages and URLs.&amp;nbsp; This avoids the risk of a hacker trying to intercept the authentication cookie on a non-SSL secured page, and then trying to use a "replay attack" from a different machine to impersonate a user.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;For more information on IIS 7.0, please &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/04/02/iis-7-0.aspx" target="_blank"&gt;read my earlier IIS 7.0 overview blog post&lt;/a&gt;.&amp;nbsp; Also make sure to check out the &lt;a href="http://www.iis.net"&gt;www.iis.net&lt;/a&gt; website.&amp;nbsp; &lt;/p&gt; &lt;p&gt;To read more of my "Tips and Tricks" blog posts, please visit my &lt;a href="http://weblogs.asp.net/scottgu/pages/ASP.NET-2.0-Tips_2C00_-Tricks_2C00_-Recipes-and-Gotchas.aspx" target="_blank"&gt;Tips and Tricks Summary Page&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Hope this helps,&lt;/p&gt; &lt;p&gt;Scott&lt;/p&gt;&lt;/font&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=2186474" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/IIS7/default.aspx">IIS7</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category></item><item><title>JSON Hijacking and How ASP.NET AJAX 1.0 Avoids these Attacks</title><link>http://weblogs.asp.net/scottgu/archive/2007/04/04/json-hijacking-and-how-asp-net-ajax-1-0-mitigates-these-attacks.aspx</link><pubDate>Wed, 04 Apr 2007 18:39:55 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:2178123</guid><dc:creator>ScottGu</dc:creator><slash:comments>36</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=2178123</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2007/04/04/json-hijacking-and-how-asp-net-ajax-1-0-mitigates-these-attacks.aspx#comments</comments><description>&lt;font face="arial" size="2"&gt; &lt;p&gt;Recently some reports have been issued by security researchers describing ways hackers can use the JSON wire format used by most popular AJAX frameworks to try and exploit cross domain scripts within browsers.&amp;nbsp; Specifically, these attacks use HTTP GET requests invoked via&amp;nbsp;an HTML&amp;nbsp;&amp;lt;script src=""&amp;gt; include element to circumvent the "same origin policy" enforced by browsers (which limits JavaScript objects like XmlHttpRequest to only calling URLs on the same domain that the page was loaded from), and then look for ways to exploit the JSON payload content.&lt;/p&gt; &lt;p&gt;ASP.NET AJAX 1.0 includes a number of default settings and built-in features that prevent it from being susceptible to these types of JSON hijacking attacks.&amp;nbsp; Below are some details of how these attacks are mitigated:&lt;/p&gt; &lt;h5&gt;&lt;strong&gt;&lt;u&gt;ASP.NET AJAX Web Methods do not enable HTTP GET requests by default&lt;/u&gt;&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;Script files loaded via an HTML &amp;lt;script src=""&amp;gt; element within a browser can only be retrieved via HTTP GET verb requests.  &lt;p&gt;By default ASP.NET AJAX's web services layer does not allow web methods to be invoked via the HTTP GET verb. For example, assume a developer writes a web service method like below:  &lt;p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&lt;font color="black"&gt;[WebMethod]&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;public&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;StockQuote[]&amp;nbsp;GetQuotes(&lt;/font&gt;&lt;font color="blue"&gt;string&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;symbol)&amp;nbsp;{&lt;br&gt;&lt;br&gt;}&lt;br&gt;&lt;/font&gt;&lt;/div&gt; &lt;p&gt;ASP.NET will only allow the above GetQuotes method to be called via the HTTP POST verb, and will reject all attempts to invoke the method via an HTTP GET verb.  &lt;p&gt;To make an ASP.NET AJAX web-method callable via HTTP GET-access, a developer must explicitly attribute each method using ASP.NET's &lt;i&gt;ScriptMethod&lt;/i&gt; attribute (and set the UseHttpGet property to true):  &lt;p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&lt;font color="black"&gt;[WebMethod]&amp;nbsp;&lt;br&gt;[ScriptMethod(UseHttpGet&lt;/font&gt;&lt;font color="blue"&gt;=true&lt;/font&gt;&lt;font color="black"&gt;)]&amp;nbsp;&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;public&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;StockQuote[]&amp;nbsp;GetQuotes(&lt;/font&gt;&lt;font color="blue"&gt;string&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;symbol)&amp;nbsp;{&amp;nbsp;&lt;br&gt;&lt;br&gt;}&amp;nbsp;&lt;br&gt;&lt;/font&gt;&lt;/div&gt; &lt;p&gt;Although this type of modification is easy to make, it requires a developer to intentionally GET enable a web service. ASP.NET AJAX web services can never be&amp;nbsp;non-deliberately GET enabled, and&amp;nbsp;the ASP.NET AJAX documentation explicitly &lt;a href="http://ajax.asp.net/docs/overview/AsynchronousLayerOverview.aspx" target="_blank"&gt;recommends against GET enabling web-service end points&lt;/a&gt;&amp;nbsp;for a number of reasons (risk of url tampering being one of them).  &lt;p&gt;Note: the ASP.NET AJAX "UpdatePanel" control, as well as the other server controls that ship with ASP.NET AJAX 1.0, do not use HTTP GET and instead use HTTP POSTs when doing asynchronous postbacks.  &lt;h5&gt;&lt;strong&gt;&lt;u&gt;ASP.NET AJAX Content-Type Header Validation&lt;/u&gt;&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;There is a built-in validation layer of protection that ASP.NET enforces for both GET and POST based ASP.NET AJAX web methods, which is that&amp;nbsp;regardless of the HTTP verb being used, ASP.NET &lt;u&gt;always requires&lt;/u&gt; that the HTTP &lt;i&gt;Content-Type&lt;/i&gt; header is set to the value &lt;b&gt;application/json&lt;/b&gt;. It this content type header is not sent, ASP.NET AJAX will reject the request on the server.&lt;/p&gt; &lt;p&gt;Using the stock quote method shown earlier, an HTTP trace of an ASP.NET AJAX GET invocation must look like the following:&lt;/p&gt; &lt;p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;GET&amp;nbsp;/StockService/Stock.asmx/GetQuotes?symbol=%22msft%22&amp;nbsp;HTTP/1.1&amp;nbsp;&lt;br&gt;Accept:&amp;nbsp;*/*&amp;nbsp;&lt;br&gt;Accept-Language:&amp;nbsp;en-us,fr;q=0.5&amp;nbsp;&lt;br&gt;Referer:&amp;nbsp;http://xxxxxx/StockService/test.aspx&amp;nbsp;&lt;br&gt;Content-Type:&amp;nbsp;&lt;strong&gt;&lt;font color="#ff0000"&gt;application/json;&lt;/font&gt;&lt;/strong&gt;&amp;nbsp;charset=utf-8&amp;nbsp;&lt;br&gt;UA-CPU:&amp;nbsp;x86&amp;nbsp;&lt;br&gt;Accept-Encoding:&amp;nbsp;gzip,&amp;nbsp;deflate&amp;nbsp;&lt;br&gt;User-Agent:&amp;nbsp;Mozilla/4.0&amp;nbsp;(compatible;&amp;nbsp;MSIE&amp;nbsp;7.0;&amp;nbsp;Windows&amp;nbsp;NT&amp;nbsp;5.1;&amp;nbsp;.NET&amp;nbsp;CLR&amp;nbsp;1.1.4322;&amp;nbsp;.NET&amp;nbsp;CLR&amp;nbsp;2.0.50727;&amp;nbsp;InfoPath.2)&amp;nbsp;&lt;br&gt;Host:&amp;nbsp;xxxxxx&amp;nbsp;&lt;br&gt;Proxy-Connection:&amp;nbsp;Keep-Alive&amp;nbsp;&lt;br&gt;&lt;/div&gt; &lt;p&gt;Note that even though the above is a GET request, the client-side ASP.NET AJAX JSON stack still inserts a &lt;em&gt;Content-Type &lt;/em&gt;HTTP&lt;em&gt; &lt;/em&gt;header that tells the server to consider this an AJAX web service request. The server-side web services stack for ASP.NET AJAX 1.0 always checks for this specific content type, and if it is not found it will reject the request.  &lt;p&gt;If a malicious developer attempted a cross site request forgery attack using HTTP GETs against this web service, they might include a script tag in their page like the following:  &lt;p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;script&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;type&lt;/font&gt;&lt;font color="blue"&gt;="text/javascript"&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;src&lt;/font&gt;&lt;font color="blue"&gt;="http://contoso.com/StockService/Stock.asmx/GetQuotes?symbol=msft"&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;/&amp;gt;&amp;nbsp;&lt;/font&gt; &lt;/div&gt; &lt;p&gt;However, browsers&amp;nbsp;&lt;u&gt;will not&lt;/u&gt; set the &lt;i&gt;Content-Type&lt;/i&gt; to &lt;b&gt;application/json&lt;/b&gt; when parsing a &amp;lt;script src=""&amp;gt;&amp;nbsp;element and making&amp;nbsp;the request. As a result when ASP.NET receives a request made from a &amp;lt;script /&amp;gt; include, it will not recognize it as a request to an ASP.NET AJAX web service, and it will result in an error from ASP.NET stating that it does not recognize the requested URL.&amp;nbsp; This will prevent JSON Hijacking attempts (even if you have the GET verb enabled for a web method).&lt;/p&gt; &lt;h5&gt;&lt;strong&gt;&lt;u&gt;Summary&lt;/u&gt;&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;ASP.NET AJAX 1.0 by default only allows the HTTP POST verb to be used when invoking web methods using JSON, which means you can't inadvertently allow browsers to invoke methods via HTTP GET. &lt;/p&gt; &lt;p&gt;ASP.NET AJAX 1.0 requires a Content-Type header to be set to "application/json" for both GET and POST invocations to AJAX web services.&amp;nbsp; JSON requests that do not contain this header will be rejected by an ASP.NET server.&amp;nbsp; This means you cannot invoke an ASP.NET AJAX web method via a &amp;lt;script src=""&amp;gt; include because browsers do not allow append custom content-type headers when requesting a JavaScript file like this.&lt;/p&gt; &lt;p&gt;Hope this helps,&lt;/p&gt; &lt;p&gt;Scott&lt;/p&gt;&lt;/font&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=2178123" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/.NET/default.aspx">.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Atlas/default.aspx">Atlas</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category></item><item><title>Tip/Trick: Integrating ASP.NET Security with Classic ASP and Non-ASP.NET URLs</title><link>http://weblogs.asp.net/scottgu/archive/2007/03/04/tip-trick-integrating-asp-net-security-with-classic-asp-and-non-asp-net-urls.aspx</link><pubDate>Mon, 05 Mar 2007 02:17:38 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:1906243</guid><dc:creator>ScottGu</dc:creator><slash:comments>22</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=1906243</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2007/03/04/tip-trick-integrating-asp-net-security-with-classic-asp-and-non-asp-net-urls.aspx#comments</comments><description>&lt;font face="arial" size="2"&gt; &lt;p&gt;One of the questions I am often asked is "How can I integrate ASP.NET security with Classic ASP other non-ASP.NET URLs?".&amp;nbsp; Specifically,&amp;nbsp;people want to know if they can&amp;nbsp;integrate ASP.NET's Forms Authentication, Role Based Security, and URL Authorization features with Classic ASP, PHP, JSP, .HTM, .JPG&amp;nbsp;and other non-ASP.NET URLs.&lt;/p&gt; &lt;p&gt;The good news is that this is pretty easy with ASP.NET 2.0 and IIS 6.0 today, and will get even easier in the IIS 7.0 timeframe.&amp;nbsp; The below blog post demonstrates how to integrate ASP.NET 2.0's Forms Authentication and Login/Membership features with classic ASP and static .HTML files.&amp;nbsp; &lt;/p&gt; &lt;p&gt;For a much more detailed walkthrough of how to achieve this (as well as how to integrate features like ASP.NET role&amp;nbsp;based authorization&amp;nbsp;with classic ASP applications), please read Chapter 6 of Stefan Schackow's excellent &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0764596985/ref=nosim/theplanningsh-20" target="_blank"&gt;ASP.NET 2.0 Security, Membership, and Role Management&lt;/a&gt; book.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Some Background on IIS 6.0 Wildcard Mappings&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;IIS 6.0 with Windows Server 2003&amp;nbsp;added support for an ISAPI&amp;nbsp;feature called "wildcard mappings".&amp;nbsp; Wildcard mappings provide a way to configure IIS to cause all requests coming into the server to first be routed to one or more ISAPI extensions for processing.&amp;nbsp; What is cool about wildcard mappings in IIS 6.0 is that after the ISAPI extension that is processing the wildcard extension is finished, it&amp;nbsp;can then cause IIS to pass control of the request to the extension or internal handler within IIS that normally would process the request.&lt;/p&gt; &lt;p&gt;ASP.NET 2.0 includes built-in support to take advantage of this wildcard mapping feature.&amp;nbsp; This enables you to run ASP.NET code&amp;nbsp;(or your own custom code) before &lt;em&gt;and&lt;/em&gt; after the existing ISAPI extension that processes a non-ASP.NET URL (for example: a .asp, .php or .htm request) executes.&lt;/p&gt; &lt;p&gt;We can use this feature to enable a bunch of cool integration features - including using ASP.NET authentication and authorization features to secure all URLs on&amp;nbsp;a web-server.&amp;nbsp; &lt;/p&gt; &lt;p&gt;&lt;strong&gt;How to Configure an IIS 6.0 Wildcard Mapping &lt;/strong&gt;&lt;/p&gt; &lt;p&gt;For this sample I've created a new IIS application within the IIS 6.0 admin tool called "wildcardtest".&amp;nbsp; It points to a directory that will contain a few files: "default.aspx", "login.aspx", "test.asp" and "test.htm" (these last two files being resources not usually handled by ASP.NET):&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/classicaspauth/step1.jpg"&gt; &lt;/p&gt; &lt;p&gt;By default when a URL request for a .aspx page comes to the application, the ASP.NET ISAPI will process the request.&amp;nbsp; By default when a URL request for test.asp comes to the application, the classic ASP ISAPI will process the request - and no ASP.NET code will run.&amp;nbsp; When a URL request for test.htm comes to the application, IIS6 will process the request internally - and again no ASP.NET code will ever run.&lt;/p&gt; &lt;p&gt;We'll change this by enabling wildcard mappings for this application, and configure ASP.NET to run code before and after all requests to the server.&amp;nbsp; To-do this, right-click on the application within the IIS Admin Tool and select the "properties" context menu item on it.&amp;nbsp; This will bring up the application properties dialog:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/classicaspauth/step2.jpg"&gt; &lt;/p&gt; &lt;p&gt;You can then click the "configuration" button to pull up the URL mapping rules for the application:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/classicaspauth/step3.jpg"&gt; &lt;/p&gt; &lt;p&gt;Note how the top of this dialog lists the default ISAPI extension mappings (each URL extension is mapped to an ISAPI responsible for processing it).&amp;nbsp; The bottom half of the dialog lists the "wildcard application map" rules.&amp;nbsp; We can add a application wildcard mapping to the ASP.NET ISAPI by clicking the "insert" button, and pointing at the ASP.NET 2.0 ISAPI extension on disk:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/classicaspauth/step4.jpg"&gt; &lt;/p&gt; &lt;p&gt;&lt;u&gt;Very, Very&amp;nbsp;Important&lt;/u&gt;: Make sure that you &lt;em&gt;uncheck&lt;/em&gt; the "Verify this file exists" checkbox.&amp;nbsp; If you don't do this ASP.NET URL resources like WebResource.axd and other URL's handled by ASP.NET that aren't backed by a physical file won't work anymore.&amp;nbsp; This will lead to errors within your pages.&lt;/p&gt; &lt;p&gt;Now close out all of the dialogs by clicking "ok" to accept the changes.&amp;nbsp; You've now configured ASP.NET to be able to run code before and after each URL request into the application.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Enabling Forms Authentication and Url Authorization for non-ASP.NET resources&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Once we've completed the above steps to register ASP.NET 2.0 as a wild-card mapping for all URLs into our IIS application, we can then use the standard ASP.NET authentication and authorization techniques to identify users in our application and grant/deny them access to it.&lt;/p&gt; &lt;p&gt;For example, we could add a web.config file to our application that enables ASP.NET's forms authentication feature for this application, and sets up two URL Authorization rules that deny "anonymous" users access to both the test.asp and test.htm URLs:&lt;/p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;?xml&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;version&lt;/font&gt;&lt;font color="blue"&gt;="1.0"?&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;configuration&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;system.web&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;authentication&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;mode&lt;/font&gt;&lt;font color="blue"&gt;="Forms"&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;/&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;system.web&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;location&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;path&lt;/font&gt;&lt;font color="blue"&gt;="test.asp"&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;system.web&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;authorization&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;deny&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;users&lt;/font&gt;&lt;font color="blue"&gt;="?"/&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;allow&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;users&lt;/font&gt;&lt;font color="blue"&gt;="*"/&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;authorization&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;system.web&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;location&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;location&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;path&lt;/font&gt;&lt;font color="blue"&gt;="test.htm"&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;system.web&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;authorization&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;deny&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;users&lt;/font&gt;&lt;font color="blue"&gt;="?"/&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;allow&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;users&lt;/font&gt;&lt;font color="blue"&gt;="*"/&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;authorization&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;system.web&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;location&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;configuration&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;/font&gt; &lt;/div&gt; &lt;p&gt;Now, when I attempt to access either "test.asp" or "test.htm", the ASP.NET authentication and authorization system will execute first to check whether I'm logged into the application with forms-authentication, and if not redirect me to the login.aspx page within my application for me to login:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/classicaspauth/step5.jpg"&gt; &lt;/p&gt; &lt;p&gt;Note how the "ReturnUrl" used by ASP.NET's forms authentication system above has automatically set the "test.asp" url to redirect back to once I'm logged in (this works just like it would for a .aspx page).&amp;nbsp; Once I successfully enter a username/password, I'll then have access to the test.asp page:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.scottgu.com/blogposts/classicaspauth/step6.jpg"&gt; &lt;/p&gt; &lt;p&gt;Since the above page is a classic ASP file, I obviously don't have a "User.Identity.Name" property that I can use to identify the logged in user like I would in an ASP.NET page.&amp;nbsp; However, I can retrieve the "AUTH_USER" ServerVariable value within classic ASP to obtain the username (ASP.NET automatically populates this before delegating the processing back to the classic ASP ISAPI).&amp;nbsp; &lt;/p&gt; &lt;p&gt;The code to use this from within classic ASP would look like below:&lt;/p&gt; &lt;p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;html&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;body&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;h1&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;Classic&amp;nbsp;ASP&amp;nbsp;Page&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;h1&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;h3&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;You&amp;nbsp;are&amp;nbsp;logged&amp;nbsp;in&amp;nbsp;as:&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;u&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;span style="background-color: #ffff99"&gt;&lt;font color="black"&gt;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;%=Request.ServerVariables("AUTH_USER")&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;%&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;/font&gt;&lt;/span&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;u&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;h3&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;body&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;html&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;/font&gt; &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.scottgu.com/blogposts/classicaspauth/wildcard.zip"&gt;Click here&lt;/a&gt; to download a complete sample application that implements the above solution.&amp;nbsp; By default it will use a SQL Express database to store ASP.NET 2.0's Membership and Role Management data.&amp;nbsp; Alternatively, you can create and register a SQL 2000 or SQL 2005 database to store the membership and role management values.&amp;nbsp; &lt;a href="http://weblogs.asp.net/scottgu/archive/2005/08/25/423703.aspx" target="_blank"&gt;This older ASP.NET Security tutorial&lt;/a&gt; I did shows how to-do this.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;How to Learn More about ASP.NET Security&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;I highly recommend buying a copy of Stefan Schackow's excellent &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0764596985/ref=nosim/theplanningsh-20" target="_blank"&gt;ASP.NET 2.0 Security, Membership, and Role Management&lt;/a&gt; book.&amp;nbsp; Stefan is a key&amp;nbsp;member of the ASP.NET team, and owned and designed the security features in the ASP.NET 2.0 release.&amp;nbsp; As such, he &lt;em&gt;really, really, really&lt;/em&gt;&amp;nbsp;knows what he is writing about.&amp;nbsp; &lt;/p&gt; &lt;p&gt;Chapter 6 of his book is titled "Integrating ASP.NET Security with Classic ASP" and contains much more detail about the solution I demonstrated above&amp;nbsp;(as well as how to use role security with it, and pass data back and forth between ASP.NET and classic ASP).&amp;nbsp; &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.amazon.com/exec/obidos/ASIN/0764596985/ref=nosim/theplanningsh-20"&gt;&lt;img src="http://ec1.images-amazon.com/images/P/0764596985.01._BO2,204,203,200_PIsitb-dp-500-arrow,TopRight,45,-64_OU01_AA240_SH20_SCLZZZZZZZ_.jpg"&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.amazon.com/exec/obidos/ASIN/0764596985/ref=nosim/theplanningsh-20" target="_blank"&gt;Click here&lt;/a&gt; to learn more about the book and/or buy it online.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Other Online ASP.NET Security Resources&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;I've published a number of ASP.NET Tips, Tricks, Recipes&amp;nbsp;and Tutorials in the past that cover ASP.NET 2.0 security.&amp;nbsp; Below is a short-list of them that you might want to review:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/02/24/ASP.NET-2.0-Membership_2C00_-Roles_2C00_-Forms-Authentication_2C00_-and-Security-Resources-.aspx"&gt;Resource: ASP.NET 2.0 Membership, Roles, Forms Authentication, and Security Resources &lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/07/12/Recipe_3A00_-Enabling-Windows-Authentication-within-an-Intranet-ASP.NET-Web-application.aspx"&gt;Recipe: Enabling Windows Authentication within an Intranet ASP.NET Web application&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/07/23/Recipe_3A00_-Implementing-Role-Based-Security-with-ASP.NET-using-Windows-Authentication-and-SQL-Server.aspx"&gt;Recipe: Implementing Role Based Security with ASP.NET using Windows Authentication and SQL Server&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2005/08/25/423703.aspx"&gt;Recipe: Configuring ASP.NET 2.0 Application Services to use SQL Server 2000 or SQL Server 2005&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/04/22/Always-set-the-_2200_applicationName_2200_-property-when-configuring-ASP.NET-2.0-Membership-and-other-Providers.aspx"&gt;Gotcha: Always set the "applicationName" property when configuring ASP.NET 2.0 Membership and other Providers&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/11/20/common-gotcha-don-t-forget-to-clear-when-adding-providers.aspx"&gt;Common Gotcha: Don't forget to &amp;lt;clear/&amp;gt; when adding providers&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/10/13/Tip_2F00_Trick_3A00_-Source_2F00_Documentation-for-Simple-ASP.NET-2.0-SQL-Providers-Published.aspx"&gt;Tip/Trick: Source/Documentation for Simple ASP.NET 2.0 SQL Providers Published&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/09/30/Tip_2F00_Trick_3A00_-Guard-Against-SQL-Injection-Attacks.aspx"&gt;Tip/Trick: Guard Against SQL Injection Attacks&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/07/05/Tip_2F00_Trick_3A00_-Gathering-Custom-User-Registration-Information.aspx"&gt;Tip/Trick: Gathering Custom User Registration Information&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2005/10/18/427754.aspx"&gt;Recipe: How to add a Login, Roles and Profile system to an ASP.NET 2.0 app in only 24 lines of code&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/01/31/437027.aspx"&gt;Gotcha: Authorization with the built-in VS 2005 Web Server (aka Cassini)&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2005/11/08/430011.aspx"&gt;Gotcha: Forms Authentication timeout default changed between ASP.NET 1.1 -&amp;gt; ASP.NET 2.0&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2005/12/10/432851.aspx"&gt;Tip/Trick: How To Share Authentication Cookies across ASP.NET V1.1 and ASP.NET V2.0 Applications&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;For more free ASP.NET Tips, Tricks, and Tutorials I've written, please check out my &lt;a href="http://weblogs.asp.net/scottgu/pages/ASP.NET-2.0-Tips_2C00_-Tricks_2C00_-Recipes-and-Gotchas.aspx" target="_blank"&gt;ASP.NET Tips, Tricks and Tutorials listing&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Hope this helps,&lt;/p&gt; &lt;p&gt;Scott&lt;/p&gt;&lt;/font&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=1906243" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/IIS7/default.aspx">IIS7</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category></item><item><title>Common Gotcha: Don't forget to &lt;clear/&gt; when adding providers</title><link>http://weblogs.asp.net/scottgu/archive/2006/11/20/common-gotcha-don-t-forget-to-clear-when-adding-providers.aspx</link><pubDate>Tue, 21 Nov 2006 07:22:47 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:975134</guid><dc:creator>ScottGu</dc:creator><slash:comments>17</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=975134</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2006/11/20/common-gotcha-don-t-forget-to-clear-when-adding-providers.aspx#comments</comments><description>&lt;font face="arial" size="2"&gt; &lt;p&gt;Recently I've helped a few people out who were having an issue with how they had added new Membership, Role, and Profile providers within their web.config file.&amp;nbsp; If you are ever going to add a provider declaration within your web.config file, please read-on to learn how to avoid a common gotcha.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;You want to configure ASP.NET 2.0 to store your Membership/Role Management/Profile data within a remote SQL database.&amp;nbsp; To accomplish this you &lt;a href="http://weblogs.asp.net/scottgu/archive/2005/08/25/423703.aspx" target="_blank"&gt;first use the aspnet_regsql.exe utility&lt;/a&gt; to provision the appropriate schema within the database.&amp;nbsp; Rather than override the "LocalSqlServer" connection string within your web.config file, you decide to register a new provider within your web.config file like below (note: the following registration has a bug - so don't copy/paste it):&lt;/p&gt; &lt;p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;membership&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;providers&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;add&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;name&lt;/font&gt;&lt;font color="blue"&gt;="AspNetSqlMembershipProvider"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type&lt;/font&gt;&lt;font color="blue"&gt;="System.Web.Security.SqlMembershipProvider,&amp;nbsp;System.Web,&amp;nbsp;Version=2.0.0.0,&amp;nbsp;Culture=neutral,&amp;nbsp;PublicKeyToken=b03f5f7f11d50a3a"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;connectionStringName&lt;/font&gt;&lt;font color="blue"&gt;="MyDatabase"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enablePasswordRetrieval&lt;/font&gt;&lt;font color="blue"&gt;="false"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enablePasswordReset&lt;/font&gt;&lt;font color="blue"&gt;="true"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;requiresQuestionAndAnswer&lt;/font&gt;&lt;font color="blue"&gt;="true"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; requiresUniqueEmail&lt;/font&gt;&lt;font color="blue"&gt;="false"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passwordFormat&lt;/font&gt;&lt;font color="blue"&gt;="Hashed"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maxInvalidPasswordAttempts&lt;/font&gt;&lt;font color="blue"&gt;="5"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minRequiredPasswordLength&lt;/font&gt;&lt;font color="blue"&gt;="7"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minRequiredNonalphanumericCharacters&lt;/font&gt;&lt;font color="blue"&gt;="1"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passwordAttemptWindow&lt;/font&gt;&lt;font color="blue"&gt;="10"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passwordStrengthRegularExpression&lt;/font&gt;&lt;font color="blue"&gt;=""&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;applicationName&lt;/font&gt;&lt;font color="blue"&gt;="/"&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;/&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;providers&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;membership&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;/font&gt; &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;When registering the above provider &lt;a href="http://weblogs.asp.net/scottgu/archive/2006/04/22/Always-set-the-_2200_applicationName_2200_-property-when-configuring-ASP.NET-2.0-Membership-and-other-Providers.aspx" target="_blank"&gt;you are careful to explictly set the applicationName property, and so avoid another really common gotcha&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;When you run your application on a machine without SQL Express, though, you see some weird behavior.&amp;nbsp; You might get a SQL error like so:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;i&gt;An error has occurred while establishing a connection to the server. &amp;nbsp;When connecting to SQL Server 2005, this failure may be caused by the fact that under the default settings SQL Server does not allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)&lt;/i&gt; &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;You might also find that the web administration tool has problems connecting with your database and/or the roles/users you create within it aren't correctly saved in the database you configured above.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Cause of the Problem:&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;The root cause of the above problem rests in how the new provider was registered within the web.config file.&amp;nbsp; &lt;/p&gt; &lt;p&gt;The &amp;lt;providers&amp;gt; section within the web.config file is implemented as a collection, and so it is possible to register multiple providers at the same time (this is useful when you want to have some users authenticated using one Membership store, and others authenticated using a separate Membership store). &lt;/p&gt; &lt;p&gt;By default ASP.NET 2.0 registers a set of default SQL Express providers within the root web.config file on your machine that create a SQL Express database within your /app_data directory to store/manage membership/role/profile data when you first access it.&amp;nbsp; Because this is registered at the machine-wide level, all provider collections by default inherit this registration.&amp;nbsp; Unless you explictly &amp;lt;clear/&amp;gt; or override the inherited value, your application will have this default membership/role/profile provider registered.&lt;/p&gt; &lt;p&gt;Because the above web.config file simply added a new provider --&amp;nbsp;and &lt;strong&gt;didn't&lt;/strong&gt; clear or replace&amp;nbsp;the default provider registration --&amp;nbsp;the above application now has two Membership providers configured.&amp;nbsp; When you do a Membership.CreateUser() call in your code, ASP.NET will&amp;nbsp;attempt to create the user in both membership databases.&amp;nbsp; If you don't have SQL Express installed on your system, the create-user attempt will fail for this database - which leads to the errors and/or weird behavior above.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;How to Fix It:&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Unless you wish to register multiple membership, role or profile databases (which is rare), you should always add an explicit &amp;lt;clear/&amp;gt; directive before your &amp;lt;add/&amp;gt; statements within your web.config file:&lt;/p&gt; &lt;p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;membership&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;providers&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;clear&lt;/font&gt;&lt;font color="blue"&gt;/&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;add&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;name&lt;/font&gt;&lt;font color="blue"&gt;="AspNetSqlMembershipProvider"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type&lt;/font&gt;&lt;font color="blue"&gt;="System.Web.Security.SqlMembershipProvider,&amp;nbsp;System.Web,&amp;nbsp;Version=2.0.0.0,&amp;nbsp;Culture=neutral,&amp;nbsp;PublicKeyToken=b03f5f7f11d50a3a"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;connectionStringName&lt;/font&gt;&lt;font color="blue"&gt;="MyDatabase"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enablePasswordRetrieval&lt;/font&gt;&lt;font color="blue"&gt;="false"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enablePasswordReset&lt;/font&gt;&lt;font color="blue"&gt;="true"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;requiresQuestionAndAnswer&lt;/font&gt;&lt;font color="blue"&gt;="true"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; requiresUniqueEmail&lt;/font&gt;&lt;font color="blue"&gt;="false"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passwordFormat&lt;/font&gt;&lt;font color="blue"&gt;="Hashed"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maxInvalidPasswordAttempts&lt;/font&gt;&lt;font color="blue"&gt;="5"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minRequiredPasswordLength&lt;/font&gt;&lt;font color="blue"&gt;="7"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minRequiredNonalphanumericCharacters&lt;/font&gt;&lt;font color="blue"&gt;="1"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passwordAttemptWindow&lt;/font&gt;&lt;font color="blue"&gt;="10"&lt;/font&gt;&lt;font color="red"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passwordStrengthRegularExpression&lt;/font&gt;&lt;font color="blue"&gt;=""&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;applicationName&lt;/font&gt;&lt;font color="blue"&gt;="/"&lt;/font&gt;&lt;font color="red"&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;/&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;providers&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="maroon"&gt;membership&lt;/font&gt;&lt;font color="blue"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;&lt;/font&gt; &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;This will ensure that your application doesn't inherit any default provider registrations.&amp;nbsp; &lt;/p&gt; &lt;p&gt;Note that you must do this for each provider declaration that you register.&amp;nbsp; So if you are adding providers for &amp;lt;roles&amp;gt; and &amp;lt;profile&amp;gt;, make sure you add the &amp;lt;clear/&amp;gt; directive in their providers section as well.&lt;/p&gt; &lt;p&gt;Hope this helps,&lt;/p&gt; &lt;p&gt;Scott&lt;/p&gt; &lt;p&gt;P.S. &lt;a href="http://weblogs.asp.net/scottgu/pages/ASP.NET-2.0-Tips_2C00_-Tricks_2C00_-Recipes-and-Gotchas.aspx" target="_blank"&gt;Click here to review other past ASP.NET Tips/Tricks, Gotchas, and Recipes&lt;/a&gt;.&lt;/p&gt;&lt;/font&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=975134" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/.NET/default.aspx">.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category></item><item><title>Tip/Trick: Source/Documentation for Simple ASP.NET 2.0 SQL Providers Published</title><link>http://weblogs.asp.net/scottgu/archive/2006/10/13/Tip_2F00_Trick_3A00_-Source_2F00_Documentation-for-Simple-ASP.NET-2.0-SQL-Providers-Published.aspx</link><pubDate>Sat, 14 Oct 2006 04:36:56 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:661147</guid><dc:creator>ScottGu</dc:creator><slash:comments>15</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=661147</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2006/10/13/Tip_2F00_Trick_3A00_-Source_2F00_Documentation-for-Simple-ASP.NET-2.0-SQL-Providers-Published.aspx#comments</comments><description>&lt;font face="arial" size="2"&gt; &lt;p&gt;One of the most popular features in ASP.NET 2.0 was the introduction of the "provider model" for the built-in ASP.NET Application Service APIs.&amp;nbsp; The provider model ensures that the storage/implementation for services like Membership, Roles, Profiles, Health Monitoring, Session State, and Site Navigation is extensible, and it allows a developer to easily plug-in alternative implementations if they want.&amp;nbsp; &lt;/p&gt; &lt;p&gt;Earlier this year &lt;a href="http://weblogs.asp.net/scottgu/archive/2006/04/13/Source-Code-for-the-Built_2D00_in-ASP.NET-2.0-Providers-Now-Available-for-Download.aspx" target="_blank"&gt;I blogged about how we shipped the source code for the built-in ASP.NET 2.0 Providers on MSDN&lt;/a&gt;, and published 130+ pages of really good documentation that walksthrough their implementation and behavior.&amp;nbsp; If you are looking to adapt the existing providers (which are pretty feature rich and in-depth), then you'll find these whitepapers and source&amp;nbsp;a good resource to check-out.&amp;nbsp; One downside with starting off with the code within the built-in feature-rich/optimized providers, though,&amp;nbsp;is that the source code might be bigger and more complicated then you might like, and the database schema might not map to the database structure you want.&amp;nbsp; &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.aspnet.cz/" target="_blank"&gt;Michal Valasek&lt;/a&gt; sent me mail earlier today pointing me at a &lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=AltairisWebProviders" target="_blank"&gt;really cool CodePlex project&lt;/a&gt; he has started that provides a simplified set of SQL Provider implementations for the ASP.NET Membership, Roles and Profile APIs.&amp;nbsp; These use a nice straight-forward database schema and can be easily adapted for your application and/or integrated into existing tables you might already have.&amp;nbsp; You can download the source code for them &lt;a href="http://www.codeplex.com/SourceControl/ListDownloadableCommits.aspx?ProjectName=AltairisWebProviders" target="_blank"&gt;here&lt;/a&gt;.&amp;nbsp; I definitely recommend checking them out and bookmarking the project - they provide a really great way to get started with custom providers.&lt;/p&gt; &lt;p&gt;For learning more about the ASP.NET Provider Model, I also recommend checking out a great Code-Camp presentation that Paul Wilson did complete with a nice provider implementation built with his &lt;a href="http://www.ormapper.net/" target="_blank"&gt;ORMapper&lt;/a&gt; that you &lt;a href="http://weblogs.asp.net/pwilson/archive/2006/05/14/446372.aspx" target="_blank"&gt;can download here&lt;/a&gt;.&amp;nbsp; You can also find other non-SQL provider implementations (including ones for MySql, SqlLite, Access and more) via my &lt;a href="http://weblogs.asp.net/scottgu/archive/2006/02/24/ASP.NET-2.0-Membership_2C00_-Roles_2C00_-Forms-Authentication_2C00_-and-Security-Resources-.aspx" target="_blank"&gt;ASP.NET Security Resources Page&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Hope this helps,&lt;/p&gt; &lt;p&gt;Scott&lt;/p&gt;&lt;/font&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=661147" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category></item><item><title>Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes</title><link>http://weblogs.asp.net/scottgu/archive/2006/10/04/Tip_2F00_Trick_3A00_-Adding-Authorization-Rules-to-Business-and-Data-Layers-using-PrincipalPermissionAttributes.aspx</link><pubDate>Wed, 04 Oct 2006 15:50:07 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:614662</guid><dc:creator>ScottGu</dc:creator><slash:comments>33</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=614662</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2006/10/04/Tip_2F00_Trick_3A00_-Adding-Authorization-Rules-to-Business-and-Data-Layers-using-PrincipalPermissionAttributes.aspx#comments</comments><description>&lt;font face="arial" size="2"&gt; &lt;p&gt;Earlier this summer I posted two tutorials on using Windows Authentication with ASP.NET:&amp;nbsp;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/07/12/Recipe_3A00_-Enabling-Windows-Authentication-within-an-Intranet-ASP.NET-Web-application.aspx?CommentPosted=true" target="_blank"&gt;Enabling Window Authentication within an Intranet ASP.NET Web Application&lt;/a&gt; and &lt;a href="http://weblogs.asp.net/scottgu/pages/Recipe_3A00_-Implementing-Role_2D00_Based-Security-with-ASP.NET-2.0-using-Windows-Authentication-and-SQL-Server.aspx" target="_blank"&gt;Implementing Role Based Security within ASP.NET using Windows Authentication and SQL Server&lt;/a&gt;.&amp;nbsp; I also linked to Scott Mitchell's great &lt;a href="http://weblogs.asp.net/scottgu/archive/2006/06/19/ASP.NET-2.0-Security_2C00_-Membership-and-Roles-Tutorials.aspx" target="_blank"&gt;ASP.NET 2.0 Security, Membership and Roles Tutorials&lt;/a&gt; that cover how to use Forms Authentication and the new Membership/Roles APIs in ASP.NET for Internet based web applications.&lt;/p&gt; &lt;p&gt;These tutorials covers how to implement authentication on your site, which is the process of identifying &lt;em&gt;who&lt;/em&gt; an incoming&amp;nbsp;user is.&amp;nbsp; They also demonstrate how to implement role based management on your site, which allows you to logically group individual users into higher-level roles or groups (for example: "admins", "friends", "subscribers", etc).&amp;nbsp; The tutorials also demonstrate how to implement authorization rules to grant or deny users/roles access to visit individual pages or URLs within a site (the roles tutorial above also demonstrates how to show/hide menu nodes based on the permissions of the incoming user).&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Adding Security Authorization Rules to Business and Data Layers&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;When you authenticate a user within an ASP.NET application, the authenticated user's identity will be automatically&amp;nbsp;flowed throughout that user's request on the server.&amp;nbsp; What this means is that you don't need to manually pass a user's identity around from method to method or class to class.&amp;nbsp; This makes it much easier to implement security authorization rules throughout your application.&lt;/p&gt; &lt;p&gt;One little known feature in .NET is the ability to have the CLR automatically use this identity information to authorize a user's capabilities before instantiating a class, or accessing a method/property on it.&amp;nbsp; This makes it easy to add clean security authorization rules to your business and data layers without having to write much code.&lt;/p&gt; &lt;p&gt;All you need to do to implement this is to use the PrincipalPermissionAttribute within the "System.Security.Permissions" namespace and decorate it on the appropriate class or member on it.&amp;nbsp; For example:&lt;/p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&lt;font color="blue"&gt;using&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;System&lt;/font&gt;&lt;font color="blue"&gt;;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;using&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;System.Security.Permissions&lt;/font&gt;&lt;font color="blue"&gt;;&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="black"&gt;[PrincipalPermission(SecurityAction.Demand,&amp;nbsp;Authenticated&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;=&amp;nbsp;true&lt;/font&gt;&lt;font color="black"&gt;)]&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;public&amp;nbsp;class&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;EmployeeManager&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[PrincipalPermission(SecurityAction.Demand,&amp;nbsp;Role&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;=&amp;nbsp;&lt;/font&gt;&lt;font color="#808080"&gt;"Manager"&lt;/font&gt;&lt;font color="black"&gt;)]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;public&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;Employee&amp;nbsp;LookupEmployee(&lt;/font&gt;&lt;font color="blue"&gt;int&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;employeeID)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// todo&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[PrincipalPermission(SecurityAction.Demand,&amp;nbsp;Role&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;=&amp;nbsp;&lt;/font&gt;&lt;font color="#808080"&gt;"HR"&lt;/font&gt;&lt;font color="black"&gt;)]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;public&amp;nbsp;void&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;AddEmployee(Employee&amp;nbsp;e)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // todo&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;}&lt;/font&gt; &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;In the above example, I have added a PrincipalPermission attribute to the "EmployeeManager" class.&amp;nbsp; By adding it I am requiring that a user must be authenticated (logged-in) before this class can be instantiated during a web request (the Authenticated=true demand enforces this).&amp;nbsp; I have also then added two additional security demands on the "LookupEmployee" and "AddEmployee" methods.&amp;nbsp; With the LookupEmployee method I am requiring that the authenticated user for the request is within the "Manager" role in order for the method to be invoked.&amp;nbsp; With the AddEmployee method I am requiring that the authenticated user for the request is within the "HR" role in order for this method to be invoked and&amp;nbsp;have a new Employee added to the system.&lt;/p&gt; &lt;p&gt;And now if I accidentally introduce a&amp;nbsp;security&amp;nbsp;hole&amp;nbsp;within my UI tier and have some code-path that allows a non-Manager/HR&amp;nbsp;employee to cause these methods to be invoked, my business tier will automatically prevent this from happening and raise a security exception.&amp;nbsp;&amp;nbsp;&lt;/p&gt; &lt;p&gt;The PrincipalPermissionAttribute isn't tied to any specific authentication mode.&amp;nbsp; It will work with Forms Authentication, Windows Authentication, Passport Authentication, or any custom authentication mode you want to invent.&amp;nbsp; It will also work with any Role implementation I might use (so if you build or plug-in your own Role Provider in ASP.NET it will just work).&lt;/p&gt; &lt;p&gt;The PrincipalPermissionAttribute type is implemented in the standard CLR mscorlib assembly that all .NET projects compile against.&amp;nbsp; So it isn't ASP.NET specific, and can be used within any application type (including Windows and Console applications).&amp;nbsp; In addition to making it more generically useful, this makes it easier to unit-test business/data libraries built with it.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Using PrincipalPermissionAttributes within Pages and Controls&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;The PrincipalPermissionAttribute can be used on any class within an application.&amp;nbsp; So in addition to using it within your business and data layers, you can also use it within ASP.NET pages or user-controls you author in your site as well.&amp;nbsp; For example, to enforce that your "MyPage" page can only be used by those within the "Manager" role, you could add a PrincipalPermission attribute to the code-behind of it (below done in VB):&lt;/p&gt; &lt;p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&lt;font color="blue"&gt;Imports&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;System.Security.Permissions&lt;br&gt;&lt;br&gt;&amp;lt;PrincipalPermission(SecurityAction.Demand,&amp;nbsp;Authenticated:&lt;/font&gt;&lt;font color="blue"&gt;=True&lt;/font&gt;&lt;font color="black"&gt;,&amp;nbsp;Role:&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="#808080"&gt;"Manager"&lt;/font&gt;&lt;font color="black"&gt;)&amp;gt;&amp;nbsp;_&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;Partial Class&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;MyPage&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;Inherits&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;System.Web.UI.Page&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;&lt;br&gt;End&amp;nbsp;Class&lt;/font&gt; &lt;/div&gt; &lt;p&gt;&lt;strong&gt;More on ASP.NET Security&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;To learn more about ASP.NET security I'd recommend checking out my &lt;a href="http://weblogs.asp.net/scottgu/archive/2006/02/24/ASP.NET-2.0-Membership_2C00_-Roles_2C00_-Forms-Authentication_2C00_-and-Security-Resources-.aspx" target="_blank"&gt;ASP.NET Security Resources list&lt;/a&gt; as well as my&amp;nbsp;&lt;a href="http://weblogs.asp.net/scottgu/pages/ASP.NET-2.0-Tips_2C00_-Tricks_2C00_-Recipes-and-Gotchas.aspx" target="_blank"&gt;ASP.NET Tips and Tricks Page&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;There are also now two dedicated books on ASP.NET 2.0 Security out there: Stefan Schackow's &lt;a href="http://www.amazon.com/gp/product/0764596985/sr=8-38/qid=1140774204/ref=sr_1_38/103-7721422-8377424?%5Fencoding=UTF8" target="_blank"&gt;Professional ASP.NET 2.0 Security, Membership and Role Management&lt;/a&gt; book and the new &lt;a href="http://www.amazon.com/gp/product/0735623317/sr=1-1/qid=1156801743/ref=sr_1_1/104-6313703-3867159?ie=UTF8&amp;amp;s=books" target="_blank"&gt;Developing More Secure Microsoft ASP.NET 2.0 Applications&lt;/a&gt; book by Dominick Baier (who runs the great &lt;a href="http://www.leastprivilege.com/"&gt;http://www.leastprivilege.com/&lt;/a&gt;&amp;nbsp;blog) that just got published this week:&lt;/p&gt; &lt;p&gt;Hope this helps,&lt;/p&gt; &lt;p&gt;Scott&lt;/p&gt;&lt;/font&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=614662" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/.NET/default.aspx">.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category></item><item><title>Tip/Trick: Guard Against SQL Injection Attacks</title><link>http://weblogs.asp.net/scottgu/archive/2006/09/30/Tip_2F00_Trick_3A00_-Guard-Against-SQL-Injection-Attacks.aspx</link><pubDate>Sat, 30 Sep 2006 16:11:03 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:598273</guid><dc:creator>ScottGu</dc:creator><slash:comments>58</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=598273</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2006/09/30/Tip_2F00_Trick_3A00_-Guard-Against-SQL-Injection-Attacks.aspx#comments</comments><description>&lt;font face="arial" size="2"&gt; &lt;p&gt;SQL Injection attacks are really&amp;nbsp;nasty security vulnerabilities, and something all web developers (regardless of platform, technology or data layer) need to make sure they understand and protect themselves against.&amp;nbsp; Unfortunately developers too often neglect putting focused time on this - and leave their applications (and worse their customers) extremely vulnerable.&lt;/p&gt; &lt;p&gt;Michael Sutton recently published &lt;a href="http://portal.spidynamics.com/blogs/msutton/archive/2006/09/26/How-Prevalent-Are-SQL-Injection-Vulnerabilities_3F00_.aspx" target="_blank"&gt;a very sobering post&lt;/a&gt; about just how widespread this issue is on the public web.&amp;nbsp; He built a C# client application that uses the Google Search API to look for sites vulnerable to SQL Injection Attacks.&amp;nbsp; The steps to achieve this were simple:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Look for sites that have querystring values (example: search for URLs with "id=" in the URL)  &lt;li&gt;Send a request to the sites identified as dynamic with an altered id= statement that adds an extra quote to attempt to cancel the SQL statement (example: id=6')  &lt;li&gt;Parse the response sent back to look for words like "SQL" and "query" - which typically indicate that the app is often sending back detailed error messages (also bad)  &lt;li&gt;Review whether the error message indicates that the parameter sent to SQL wasn't encoded correctly (in which case the site is open to SQL Injection Attacks)&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Of a random sampling of 1000 sites he found via his Google search, he detected possible SQL Injection Attack vulnerability with 11.3% of them.&amp;nbsp; That is really, really scary.&amp;nbsp; It means hackers can remotely exploit the data in those applications, retrieve any unhashed/encrypted passwords or credit-card data, and&amp;nbsp;potentially even log themselves in as administrators&amp;nbsp;to the application.&amp;nbsp; This is bad not only for the developer who built the application, but even worse for any consumer/user of the application who has provided data to the site thinking it will be secure.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;So what the heck is a SQL Injection Attack?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;There are a couple of scenarios that make SQL Injection attacks possible.&amp;nbsp; The most common cause are cases where you are dynamically constructing SQL statements without using correctly encoded parameters.&amp;nbsp; For example, consider this SQL query code that searches for Authors based on a social security number provided via a querystring:&lt;/p&gt; &lt;p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&lt;font color="blue"&gt;Dim&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;SSN&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;as&amp;nbsp;String&lt;br&gt;Dim&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;SqlQuery&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;as&amp;nbsp;String&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="black"&gt;SSN&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;=&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;Request.QueryString(&lt;/font&gt;&lt;font color="#808080"&gt;"SSN"&lt;/font&gt;&lt;font color="black"&gt;)&lt;br&gt;SqlQuery&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;=&amp;nbsp;&lt;/font&gt;&lt;font color="#808080"&gt;"SELECT&amp;nbsp;au_lname,&amp;nbsp;au_fname&amp;nbsp;FROM&amp;nbsp;authors&amp;nbsp;WHERE&amp;nbsp;au_id&amp;nbsp;=&amp;nbsp;'"&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;+&amp;nbsp;SSN&amp;nbsp;+&amp;nbsp;&lt;/font&gt;&lt;font color="#808080"&gt;"'"&lt;/font&gt; &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;If you have SQL code like the snippet above, then your entire database and application can be hacked remotely.&amp;nbsp; How?&amp;nbsp; Well in the normal scenario users will hit the site using a social security number which will be executed like so:&lt;/p&gt; &lt;p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&lt;font color="darkgreen"&gt;'&amp;nbsp;URL&amp;nbsp;to&amp;nbsp;the&amp;nbsp;page&amp;nbsp;containing&amp;nbsp;the&amp;nbsp;above&amp;nbsp;code&lt;br&gt;&lt;/font&gt;&lt;font color="black"&gt;http://mysite.com/listauthordetails.aspx?SSN&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="maroon"&gt;172&lt;/font&gt;&lt;font color="black"&gt;-&lt;/font&gt;&lt;font color="maroon"&gt;32&lt;/font&gt;&lt;font color="black"&gt;-&lt;/font&gt;&lt;font color="maroon"&gt;9999&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="darkgreen"&gt;'&amp;nbsp;SQL&amp;nbsp;Query&amp;nbsp;executed&amp;nbsp;against&amp;nbsp;the&amp;nbsp;database&amp;nbsp;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SELECT&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;au_lname,&amp;nbsp;au_fname&amp;nbsp;FROM&amp;nbsp;authors&amp;nbsp;WHERE&amp;nbsp;au_id&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;=&amp;nbsp;&lt;/font&gt;&lt;font color="darkgreen"&gt;'172-32-9999'&lt;/font&gt; &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;This does what the developer expected, and searches the database for author information filtered by the social security number.&amp;nbsp; But because the parameter value hasn't been SQL encoded, a hacker could just as easily modify the querystring value to embed additional SQL statements after the value to execute.&amp;nbsp; For example:&lt;/p&gt; &lt;p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&lt;font color="darkgreen"&gt;'&amp;nbsp;URL&amp;nbsp;to&amp;nbsp;the&amp;nbsp;page&amp;nbsp;containing&amp;nbsp;the&amp;nbsp;above&amp;nbsp;code&lt;br&gt;&lt;/font&gt;&lt;font color="black"&gt;http://mysite.com/listauthordetails.aspx?SSN&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="maroon"&gt;172&lt;/font&gt;&lt;font color="black"&gt;-&lt;/font&gt;&lt;font color="maroon"&gt;32&lt;/font&gt;&lt;font color="black"&gt;-&lt;/font&gt;&lt;font color="maroon"&gt;9999';DROP DATABASE pubs --&lt;/font&gt;&lt;font color="darkgreen"&gt;&lt;br&gt;&lt;br&gt;'&amp;nbsp;SQL&amp;nbsp;Query&amp;nbsp;executed&amp;nbsp;against&amp;nbsp;the&amp;nbsp;database&amp;nbsp;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SELECT&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;au_lname,&amp;nbsp;au_fname&amp;nbsp;FROM&amp;nbsp;authors&amp;nbsp;WHERE&amp;nbsp;au_id&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;= '';DROP&amp;nbsp;DATABASE pubs --&lt;/font&gt; &lt;/div&gt; &lt;p&gt;Notice how I was able to add&amp;nbsp;the &lt;em&gt;';DROP DATABASE pubs --&lt;/em&gt;&amp;nbsp;clause to the SSN querystring value and use it to terminate the current SQL statement (via the ";" character), and then add my own malicious SQL statement to the string, and then comment out the rest of the statement (via the "--" characters).&amp;nbsp; Because we are just manually&amp;nbsp;concatenating the SQL statement in our code, we will end up passing this to the database - which will execute first the query against the authors table, and then delete our pubs database table.&amp;nbsp; Bang - it is now gone.&lt;/p&gt; &lt;p&gt;In case you think the idea of anonymous hackers deleting your database tables is bad, that is unfortunately actually one of the better scenarios when a SQL Injection Attack is involved.&amp;nbsp; Rather than just destroy data, a hacker could instead use the above code vulnerability to perform a JOIN that retrieves all of the data within your database and displays it on the page (allowing them to retrieve username/passwords/credit-cards).&amp;nbsp;&amp;nbsp;They could also add UPDATE/INSERT statements to modify product prices, add new admin users, and really screw up your life (imagine auditing your inventory at the end of the month, only to discover that the actual number of products in your warehouse is different then what your accounting system reports...).&amp;nbsp; &lt;/p&gt; &lt;p&gt;&lt;strong&gt;How do you protect yourself?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;SQL Injection Attacks are something you need to worry about regardless of the web programming technology you are using (all web frameworks need to worry about it).&amp;nbsp; A couple of very basic rules you must always follow:&lt;/p&gt; &lt;p&gt;1) Don't construct dynamic SQL Statements without using a type-safe parameter encoding mechanism.&amp;nbsp; Most data APIs (including ADO + ADO.NET) have support for allowing you to specify the exact type of a parameter being provided (for example: string, integer, date) and can ensure that they are escaped/encoded for you to avoid hackers trying to exploit it.&amp;nbsp; &lt;u&gt;Always use these features&lt;/u&gt;.&amp;nbsp; &lt;/p&gt; &lt;p&gt;For example, with dynamic SQL using ADO.NET you could re-write the code above like below to make it safe:&lt;/p&gt; &lt;div style="border-right: white 2px ridge; padding-right: 10px; border-top: white 2px ridge; padding-left: 10px; font-size: 10pt; padding-bottom: 10px; margin: 10px; border-left: white 2px ridge; padding-top: 10px; border-bottom: white 2px ridge; font-family: courier new; background-color: #eeeeee; word-wrap: break-word"&gt;&lt;font color="black"&gt;Dim&amp;nbsp;SSN&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;as&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;String&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;=&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;Request.QueryString(&lt;/font&gt;&lt;font color="#808080"&gt;"SSN"&lt;/font&gt;&lt;font color="black"&gt;)&lt;br&gt;&lt;br&gt;Dim&amp;nbsp;cmd&amp;nbsp;As&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;new&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;SqlCommand(&lt;/font&gt;&lt;font color="#808080"&gt;"SELECT&amp;nbsp;au_lname,&amp;nbsp;au_fname&amp;nbsp;FROM&amp;nbsp;authors&amp;nbsp;WHERE&amp;nbsp;au_id&amp;nbsp;=&amp;nbsp;@au_id"&lt;/font&gt;&lt;font color="black"&gt;)&lt;br&gt;Dim&amp;nbsp;param&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;=&amp;nbsp;new&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;SqlParameter(&lt;/font&gt;&lt;font color="#808080"&gt;"au_id"&lt;/font&gt;&lt;font color="black"&gt;,&amp;nbsp;SqlDbType.VarChar)&lt;br&gt;param.Value&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;=&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;SSN&lt;br&gt;cmd.Parameters.Add(param)&lt;/font&gt; &lt;/div&gt; &lt;p&gt;This will prevent someone from trying to sneak in&amp;nbsp;additional SQL expressions (since ADO.NET above knows to string encode the au_id value), and avoid other data problems (incorrectly type-casting values, etc).&amp;nbsp; Note that the TableAdapter/DataSet designer built-into VS 2005&amp;nbsp;uses this mechanism automatically, as&amp;nbsp;do the ASP.NET 2.0 data source controls.&amp;nbsp;&lt;/p&gt; &lt;p&gt;One common misperception is that if you are using SPROCs or a ORM you are completely safe from SQL Injection Attacks.&amp;nbsp; This isn't true - you still need to make sure you are careful when you pass values to a SPROC, and/or when you escape or customize a query with an ORM that you do it in a safe way.&lt;/p&gt; &lt;p&gt;2) Always conduct a security review of your application before ever put it in production, and establish a formal security process to review all code anytime you make updates.&amp;nbsp; This later point is super important.&amp;nbsp; Too often I hear of teams that conduct a really detailed security review before going live, then have some "really minor" update they make to the site weeks/months later where they skip doing a security review ("it is just a tiny update - we'll code review it later").&amp;nbsp; &lt;u&gt;Always do a security review&lt;/u&gt;.&lt;/p&gt; &lt;p&gt;3) &lt;u&gt;Never store sensitive data in clear-text within a database&lt;/u&gt;.&amp;nbsp; My personal opinion is that passwords should always be one-way hashed (I don't even like to store them encrypted).&amp;nbsp; The ASP.NET 2.0 Membership API does this for you automatically by default (and also implements secure SALT randomization behavior).&amp;nbsp; If you decide to build your own membership database store, I'd recommend checking out the &lt;a href="http://msdn2.microsoft.com/en-us/asp.net/aa336558.aspx" target="_blank"&gt;source code for our own Membership provider implementation that we published here&lt;/a&gt;.&amp;nbsp; Also make sure to encrypt credit-card and other private data in your database.&amp;nbsp; This way even if your database was compromised, at least your customer private data can't be exploited.&lt;/p&gt; &lt;p&gt;4) Ensure you write automation unit&amp;nbsp;tests that specifically verify your data access layer and application against SQL Injection attacks.&amp;nbsp; This is really important to help catch the "it is just a tiny update so I'll be safe" scenario, and provide an additional safety layer to avoid accidentally introducing a bad security bug into your application.&lt;/p&gt; &lt;p&gt;5) Lock down your database to only grant the web application accessing it the minimal set of permissions that it needs to function.&amp;nbsp; If the web application doesn't need access to certain tables, then make sure it doesn't have permissions to them.&amp;nbsp; If it is only read-only generating reports from your account payables table then make sure you disable insert/update/delete access.&amp;nbsp; &lt;/p&gt; &lt;p&gt;&lt;strong&gt;How to Learn More&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;The Microsoft Prescriptive Architecture Guidance (PAG) team has posted a number of really good security guideline documents that you should set aside some time to read:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/PAGGuidelines0001.asp" target="_blank"&gt;ASP.NET 2.0 Security Guidelines&lt;/a&gt;  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/PAGCK0001.asp" target="_blank"&gt;ASP.NET 2.0 Security Deployment Checklist&lt;/a&gt;  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/PAGPractices0001.asp" target="_blank"&gt;ASP.NET 2.0 Security Practices at a Glance&lt;/a&gt;  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/WebAppSecurityEngIndex.asp" target="_blank"&gt;Web Application Engineering Security Index&lt;/a&gt;  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/PAGHT000027.asp" target="_blank"&gt;How to Perform a Security Code Review with Managed Code&lt;/a&gt;  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/PAGQuestionList0001.asp" target="_blank"&gt;ASP.NET 2.0 Security Question List&lt;/a&gt;  &lt;li&gt;&lt;a href="http://channel9.msdn.com/wiki/default.aspx/SecurityWiki.SecurityTrainingModules" target="_blank"&gt;ASP.NET 2.0 Security Training Modules&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;And these additional PAG How-To articles are useful for learning more about how to protect yourself against injection attacks:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpag2/html/paght000003.asp" target="_blank"&gt;How To: Protect from Form Injection Attacks with ASP.NET&lt;/a&gt;  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpag2/html/paght000002.asp" target="_blank"&gt;How To: Protect from SQL Injection Attacks with ASP.NET&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;You can also find useful ASP.NET security information from &lt;a href="http://weblogs.asp.net/scottgu/archive/2006/02/24/ASP.NET-2.0-Membership_2C00_-Roles_2C00_-Forms-Authentication_2C00_-and-Security-Resources-.aspx" target="_blank"&gt;this security blog post of mine&lt;/a&gt;, and from my &lt;a href="http://weblogs.asp.net/scottgu/pages/ASP.NET-2.0-Tips_2C00_-Tricks_2C00_-Recipes-and-Gotchas.aspx" target="_blank"&gt;ASP.NET Tips/Tricks page here&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Updated&lt;/strong&gt;: Bertrand pointed me at a &lt;a href="http://weblogs.asp.net/bleroy/archive/2004/08/18/216861.aspx" target="_blank"&gt;great post he did two years ago on SQL Injection Attacks&lt;/a&gt; that is great to read.&lt;/p&gt; &lt;p&gt;Hope this helps,&lt;/p&gt; &lt;p&gt;Scott&lt;/p&gt;&lt;/font&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=598273" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category></item><item><title>Tip/Trick: Patterns and Practices Guidance Explorer for .NET and ASP.NET</title><link>http://weblogs.asp.net/scottgu/archive/2006/09/27/Tip_2F00_Trick_3A00_-Patterns-and-Practices-Guidance-Explorer-for-.NET-and-ASP.NET.aspx</link><pubDate>Thu, 28 Sep 2006 05:16:52 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:590164</guid><dc:creator>ScottGu</dc:creator><slash:comments>10</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=590164</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2006/09/27/Tip_2F00_Trick_3A00_-Patterns-and-Practices-Guidance-Explorer-for-.NET-and-ASP.NET.aspx#comments</comments><description>&lt;font face="arial" size="2"&gt; &lt;p&gt;I &lt;a href="http://weblogs.asp.net/scottgu/archive/2006/06/29/Free-Patterns-and-Practices-Guidance-Explorer-for-ASP.NET-and-.NET.aspx" target="_blank"&gt;blogged about the cool new .NET and ASP.NET Guidance Explorer&lt;/a&gt; that the Microsoft Patterns and Practices Team has been working on back in June.&amp;nbsp; &lt;/p&gt; &lt;p&gt;Since then the team has been hard at work and recently moved the project to be hosted on CodePlex.&amp;nbsp; You can &lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=guidanceExplorer" target="_blank"&gt;visit and join the project here&lt;/a&gt;.&amp;nbsp; All source code for the Guidance Explorer UI (which is of course built using .NET and Windows Forms) can also now be downloaded for free from the CodePlex project site.&lt;/p&gt; &lt;p&gt;&lt;img height="347" src="http://www.codeplex.com/Project/FileDownload.aspx?ProjectName=guidanceExplorer&amp;amp;DownloadId=2709" width="855"&gt; &lt;/p&gt; &lt;p&gt;The Guidance Explorer provides a database of recommendations and best practices for ASP.NET, ADO.NET, and the .NET Framework that you can easily filter and search.&amp;nbsp; Particularly useful are some of the checklists you can easily follow for performance and security best practices prior to deployment.&lt;/p&gt; &lt;p&gt;You can create custom views of the library of just those recommendations you care about.&amp;nbsp; What is cool is that you can now also easily publish these custom views to your friends or other members of your team:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.codeplex.com/Project/FileDownload.aspx?ProjectName=guidanceExplorer&amp;amp;DownloadId=2710"&gt; &lt;/p&gt; &lt;p&gt;You will also be able to subscribe to feeds of guidance either on a local share or on the web:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.codeplex.com/Project/FileDownload.aspx?ProjectName=guidanceExplorer&amp;amp;DownloadId=2712"&gt; &lt;/p&gt; &lt;p&gt;Best of all, you can also now create your own recommendations and add them into the library (and share them with others).&amp;nbsp; &lt;/p&gt; &lt;p&gt;Download the project (and optionally the full source code) from its &lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=guidanceExplorer" target="_blank"&gt;CodePlex Project&lt;/a&gt; and start using it today!&lt;/p&gt; &lt;p&gt;Hope this helps,&lt;/p&gt; &lt;p&gt;Scott&lt;/p&gt;&lt;/font&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=590164" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/.NET/default.aspx">.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category></item><item><title>Tip/Trick: Show Detailed ASP.NET Error Messages to Developers (and only to Developers)</title><link>http://weblogs.asp.net/scottgu/archive/2006/08/12/Tip_2F00_Trick_3A00_-Show-Detailed-Error-Messages-to-Developers.aspx</link><pubDate>Sat, 12 Aug 2006 17:58:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:467889</guid><dc:creator>ScottGu</dc:creator><slash:comments>28</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=467889</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2006/08/12/Tip_2F00_Trick_3A00_-Show-Detailed-Error-Messages-to-Developers.aspx#comments</comments><description>&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;strong&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Problem: &lt;/span&gt;&lt;/strong&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;You are developing/maintaining an ASP.NET web-site, and would like the ability to conditionally show/hide runtime error messages depending on who the user visiting the site is.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;For a normal user visiting the site you want to be able to display a friendly error message like this when a runtime error occurs:&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;&lt;img src="http://www.scottgu.com/blogposts/application_error/step2.jpg" alt="" width="680" height="290" /&gt; &lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;But when someone within the &amp;ldquo;developers&amp;rdquo; security role of your application remotely accesses the site you want to instead show a more detailed exception stack trace error message about the problem without having to change any configuration data:&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;&lt;img src="http://www.scottgu.com/blogposts/application_error/step1.jpg" alt="" width="830" height="474" /&gt; &lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;The below post describes how to use ASP.NET&amp;rsquo;s role-based security architecture in conjunction with the Global.asax Application_Error event handler&amp;nbsp;to enable this.&lt;span&gt;&amp;nbsp; &lt;/span&gt;You can also &lt;a href="http://www.scottgu.com/blogposts/application_error/errordisplay.zip"&gt;download a sample&lt;/a&gt; I&amp;rsquo;ve built that shows how to implement this &lt;a href="http://www.scottgu.com/blogposts/application_error/errordisplay.zip"&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;strong&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Some Background Discussion on Error Handling and ASP.NET Custom Error Pages:&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;ASP.NET and .NET support a rich error-handling architecture that provides a flexible way to catch/handle errors at multiple levels within an application.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Specifically, you can catch and handle a runtime exception with a class, within a page, or on the global application level using the &lt;em&gt;Application_Error&lt;/em&gt; event handler within the Global.asax class.&lt;span&gt;&amp;nbsp; &lt;/span&gt;If a runtime exception isn&amp;rsquo;t handled/cancelled by one of these mechanisms, then ASP.NET&amp;rsquo;s Custom Error Page feature will kick-in, and an error page will be sent back to the browser accessing the application.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;ASP.NET&amp;rsquo;s Custom Error Page feature can be used to configure a &amp;ldquo;friendly error page&amp;rdquo; to be displayed to end-users in place of the standard &amp;ldquo;server error occurred&amp;rdquo; message sent back by ASP.NET.&lt;span&gt;&amp;nbsp; &lt;/span&gt;For example, the below web.config file section will cause remote users visiting the site to be redirected to a &amp;ldquo;friendlyErrorPage.htm&amp;rdquo; file anytime a runtime error occurs (note: HTTP 500 status code responses indicate runtime errors on the server):&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; color: blue; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-size: 9pt; color: maroon; font-family: 'Courier New'"&gt;customErrors&lt;/span&gt;&lt;span style="font-size: 9pt; color: blue; font-family: 'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size: 9pt; color: red; font-family: 'Courier New'"&gt;mode&lt;/span&gt;&lt;span style="font-size: 9pt; color: blue; font-family: 'Courier New'"&gt;=&lt;/span&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&amp;quot;&lt;span style="color: blue"&gt;RemoteOnly&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; color: blue; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-size: 9pt; color: maroon; font-family: 'Courier New'"&gt;error&lt;/span&gt;&lt;span style="font-size: 9pt; color: blue; font-family: 'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size: 9pt; color: red; font-family: 'Courier New'"&gt;statusCode&lt;/span&gt;&lt;span style="font-size: 9pt; color: blue; font-family: 'Courier New'"&gt;=&lt;/span&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&amp;quot;&lt;span style="color: blue"&gt;500&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt; &lt;/span&gt;&lt;span style="color: red"&gt;redirect&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;friendlyErrorPage.htm&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; color: blue; line-height: 115%; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&amp;lt;/&lt;/span&gt;&lt;span style="font-size: 9pt; color: maroon; line-height: 115%; font-family: 'Courier New'"&gt;customErrors&lt;/span&gt;&lt;span style="font-size: 9pt; color: blue; line-height: 115%; font-family: 'Courier New'"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;To learn more about how the ASP.NET Custom Errors feature works, and how to configure it, please &lt;a href="http://www.codeproject.com/aspnet/customerrorsinaspnet.asp"&gt;review this article&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;u&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Important&lt;/span&gt;&lt;/u&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;: I would recommend &lt;em&gt;never&lt;/em&gt; setting the &amp;lt;customErrors&amp;gt; mode attribute to &amp;ldquo;Off&amp;rdquo;.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Doing this will cause detailed error messages to be sent back to all normal users visiting your site.&lt;span&gt;&amp;nbsp; &lt;/span&gt;This can lead to information disclosure issues that can compromise the security of your site.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Instead, only change this setting to &amp;ldquo;On&amp;rdquo; or &amp;ldquo;RemoteOnly&amp;rdquo; (the default) and use the technique below for cases where you want to display detailed error messages to only some users.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;strong&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Solution:&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;The above &amp;lt;customErrors&amp;gt; configuration section will cause a friendly error message to be sent to the browser anytime a runtime error message occurs.&lt;span&gt;&amp;nbsp; &lt;/span&gt;This is what we want to happen anytime a normal user access the site, and will allow us to display error pages like this:&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;&lt;img src="http://www.scottgu.com/blogposts/application_error/step2.jpg" alt="" width="680" height="290" /&gt; &lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;To enable developers to instead see detailed error messages when they access the site, I can then add this code to the &lt;em&gt;Application_Error&lt;/em&gt; event handler within the Global.asax class:&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;Sub&lt;/span&gt; Application_Error(&lt;span style="color: blue"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: blue"&gt;As&lt;/span&gt; &lt;span style="color: blue"&gt;Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal&lt;/span&gt; e &lt;span style="color: blue"&gt;As&lt;/span&gt; EventArgs)&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;If&lt;/span&gt; (Context &lt;span style="color: blue"&gt;IsNot&lt;/span&gt; &lt;span style="color: blue"&gt;Nothing&lt;/span&gt;) &lt;span style="color: blue"&gt;And&lt;/span&gt; (Context.User.IsInRole(&lt;span style="color: maroon"&gt;&amp;quot;Developer&amp;quot;&lt;/span&gt;)) &lt;span style="color: blue"&gt;Then&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;Dim&lt;/span&gt; err &lt;span style="color: blue"&gt;As&lt;/span&gt; Exception = Server.GetLastError()&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Response.Clear()&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Response.Write(&lt;span style="color: maroon"&gt;&amp;quot;&amp;lt;h1&amp;gt;&amp;quot;&lt;/span&gt; &amp;amp; err.InnerException.Message &amp;amp; &lt;span style="color: maroon"&gt;&amp;quot;&amp;lt;/h1&amp;gt;&amp;quot;&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Response.Write(&lt;span style="color: maroon"&gt;&amp;quot;&amp;lt;pre&amp;gt;&amp;quot;&lt;/span&gt; &amp;amp; err.ToString &amp;amp; &lt;span style="color: maroon"&gt;&amp;quot;&amp;lt;/pre&amp;gt;&amp;quot;&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Server.ClearError()&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;End&lt;/span&gt; &lt;span style="color: blue"&gt;If&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 0pt; line-height: normal" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 9pt; line-height: 115%; font-family: 'Courier New'"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;End&lt;/span&gt; &lt;span style="color: blue"&gt;Sub&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;The above code checks to see if the current user visiting the site is within a specific security role.&lt;span&gt;&amp;nbsp; &lt;/span&gt;If so, then it retrieves the exception raised during the current request via the Server.GetLastError() method.&lt;span&gt;&amp;nbsp; &lt;/span&gt;It then clears out any&amp;nbsp;content already generated during the current request, and instead outputs the Exception details to the response.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Lastly, it clears out the Exception from the request &amp;ndash; which will prevent ASP.NET&amp;rsquo;s custom error architecture from kicking in.&lt;span&gt;&amp;nbsp; &lt;/span&gt;The result instead is a page that details the error like so:&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;&lt;img src="http://www.scottgu.com/blogposts/application_error/step1.jpg" alt="" width="830" height="474" /&gt; &lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;To learn more about how you can easily create and manage a &amp;ldquo;Developer&amp;rdquo; role like the one I&amp;rsquo;m using above, please review my previous post: &lt;a href="http://weblogs.asp.net/scottgu/archive/2006/07/23/Recipe_3A00_-Implementing-Role-Based-Security-with-ASP.NET-using-Windows-Authentication-and-SQL-Server.aspx"&gt;Implementing Role Based Security with ASP.NET using Windows Authentication and SQL Server&lt;/a&gt;.&lt;span&gt;&amp;nbsp; &lt;/span&gt;If you don&amp;rsquo;t want to store your role-mappings within a database, you can also store them within Active Directory or your own custom role-provider.&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;&lt;a href="http://www.scottgu.com/blogposts/application_error/errordisplay.zip"&gt;This sample&lt;/a&gt; demonstrates using a Windows User&amp;rsquo;s membership within the local &amp;ldquo;Administrators&amp;rdquo; group on a machine to control whether or not the detailed error message is displayed.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Note: you can perform a role-check on a local Windows group by writing: User.IsInRole(&amp;ldquo;BUILTIN\Administrators&amp;rdquo;) &amp;ndash; where the &amp;ldquo;BUILTIN&amp;rdquo; prefix indicates that it is a local group as opposed to a domain level one).&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Hope this helps,&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Scott&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;P.S. Please &lt;a href="http://weblogs.asp.net/scottgu/pages/ASP.NET-2.0-Tips_2C00_-Tricks_2C00_-Recipes-and-Gotchas.aspx"&gt;visit this page&lt;/a&gt; to read more articles within my &amp;ldquo;ASP.NET 2.0 Tips/Tricks/Recipes and Gotchas&amp;rdquo; series.&lt;/span&gt;&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=467889" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category></item><item><title>My ASP.NET 2.0 Tips, Tricks, Recipes and Gotchas "Highlights Page"</title><link>http://weblogs.asp.net/scottgu/archive/2006/08/01/My-ASP.NET-2.0-Tips_2C00_-Tricks_2C00_-Recipes-and-Gotchas-_2200_Highlights-Page_2200_.aspx</link><pubDate>Wed, 02 Aug 2006 06:32:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:462310</guid><dc:creator>ScottGu</dc:creator><slash:comments>15</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=462310</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2006/08/01/My-ASP.NET-2.0-Tips_2C00_-Tricks_2C00_-Recipes-and-Gotchas-_2200_Highlights-Page_2200_.aspx#comments</comments><description>&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Several people have sent me email lately asking for a suggested short-list of my best/favorite past blog posts to read (I&amp;rsquo;ve done 200 posts over the last 12 months and apparently it takes too long to read them all &amp;lt;g&amp;gt;).&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;I&amp;rsquo;ve put together a summary page of &lt;a href="http://weblogs.asp.net/scottgu/pages/ASP.NET-2.0-Tips_2C00_-Tricks_2C00_-Recipes-and-Gotchas.aspx"&gt;ASP.NET 2.0 Tips, Tricks, Recipes and Gotchas&lt;/a&gt; that you can check out &lt;a href="http://weblogs.asp.net/scottgu/pages/ASP.NET-2.0-Tips_2C00_-Tricks_2C00_-Recipes-and-Gotchas.aspx"&gt;here&lt;/a&gt;.&lt;span&gt;&amp;nbsp; &lt;/span&gt;It currently contains links to 37 posts that I&amp;rsquo;ve done in the past that I think are interesting and worth spending sometime to read.&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;I&amp;rsquo;ve organized the list by area topic (UI, Data, Security, Visual Studio, etc).&lt;span&gt;&amp;nbsp; &lt;/span&gt;My goal is to post at least 1-2 new/original ASP.NET Tips/Tricks/Recipes to my blog each week going forward.&lt;span&gt;&amp;nbsp; &lt;/span&gt;I&amp;rsquo;ll also make sure to update the summary page above as I add new ones &amp;ndash; so you might find it useful to bookmark if you want to quickly look them up.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Hope this helps,&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Scott&lt;/span&gt;&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=462310" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/LINQ/default.aspx">LINQ</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Atlas/default.aspx">Atlas</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Talks/default.aspx">Talks</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Data/default.aspx">Data</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category></item><item><title>Recipe: Implementing Role Based Security with ASP.NET using Windows Authentication and SQL Server</title><link>http://weblogs.asp.net/scottgu/archive/2006/07/23/Recipe_3A00_-Implementing-Role-Based-Security-with-ASP.NET-using-Windows-Authentication-and-SQL-Server.aspx</link><pubDate>Mon, 24 Jul 2006 04:32:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:460018</guid><dc:creator>ScottGu</dc:creator><slash:comments>54</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=460018</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2006/07/23/Recipe_3A00_-Implementing-Role-Based-Security-with-ASP.NET-using-Windows-Authentication-and-SQL-Server.aspx#comments</comments><description>&lt;h2&gt;&lt;strong&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Problem&lt;/span&gt;&lt;/strong&gt;&lt;/h2&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;You are building an Intranet expense report application for your organization, and want to enable role-based authentication and authorization capabilities within it.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Specifically, you want to create logical roles called &amp;ldquo;approvers&amp;rdquo;, &amp;ldquo;auditors&amp;rdquo;, and &amp;ldquo;administrators&amp;rdquo; for the application, and grant/deny end-users access to functionality within the application based on whether they are in these roles.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Because your application is an Intranet solution, you want to use Windows Authentication to login the users accessing the application (avoiding them having to manually login).&lt;span&gt;&amp;nbsp; &lt;/span&gt;However, because the roles you want to define are specific to your application, you do not want to define or store them within your network&amp;rsquo;s Windows Active Directory.&amp;nbsp; &lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Instead, you want to define and store these roles within a database. &lt;span&gt;&amp;nbsp;&lt;/span&gt;You then want to map Windows user accounts stored within Active Directory to these roles, and grant/deny access within the application based on them.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;In addition to using roles to authorize access to individual pages within the application, you want to dynamically filter the links displayed within the site&amp;rsquo;s menu navigation based on whether users have permissions (or not) to those links.&lt;span&gt;&amp;nbsp; &lt;/span&gt;And lastly, you want to build-in a custom role-management administration UI directly within the expense report application for &amp;ldquo;expense app administrators&amp;rdquo; to manage these roles and control who has access to the capabilities of the app:&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;&lt;img src="http://www.scottgu.com/blogposts/windowsroles/step6.jpg" alt="" width="713" height="448" /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;&lt;strong&gt;Solution&lt;/strong&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;I&amp;#39;ve put together a &lt;a href="http://weblogs.asp.net/scottgu/pages/Recipe_3A00_-Implementing-Role_2D00_Based-Security-with-ASP.NET-2.0-using-Windows-Authentication-and-SQL-Server.aspx" target="_blank"&gt;&lt;font color="#006666"&gt;detailed post&lt;/font&gt;&lt;/a&gt; that walks through step-by-step how to implement all of this.&amp;nbsp; You can &lt;a href="http://weblogs.asp.net/scottgu/pages/Recipe_3A00_-Implementing-Role_2D00_Based-Security-with-ASP.NET-2.0-using-Windows-Authentication-and-SQL-Server.aspx" target="_blank"&gt;&lt;font color="#006666"&gt;read it here&lt;/font&gt;&lt;/a&gt;, and download the completed sample I walk through how to build &lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;&lt;a href="http://www.scottgu.com/blogposts/windowsroles/sample.zip"&gt;&lt;font color="#006666"&gt;here&lt;/font&gt;&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Hope this helps,&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0in 0in 10pt" class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: 'Arial','sans-serif'"&gt;Scott&lt;/span&gt;&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=460018" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category></item><item><title>Remote Membership/Roles Management of ASP.NET 2.0 Applications</title><link>http://weblogs.asp.net/scottgu/archive/2006/07/18/Remote-Membership_2F00_Roles-Management-of-ASP.NET-2.0-Applications.aspx</link><pubDate>Tue, 18 Jul 2006 15:58:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:458844</guid><dc:creator>ScottGu</dc:creator><slash:comments>26</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=458844</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2006/07/18/Remote-Membership_2F00_Roles-Management-of-ASP.NET-2.0-Applications.aspx#comments</comments><description>&lt;font face="arial" size="2"&gt;&lt;p&gt;&lt;a href="http://peterkellner.net/" target="_blank"&gt;Peter Kellner&lt;/a&gt; recently published parts&amp;nbsp;3 and 4 of his popular how-to series on building&amp;nbsp;a custom remote security management application for ASP.NET 2.0&amp;#39;s Membership and Roles feature.&amp;nbsp; Part 3 covers Ajax enabling it with Atlas, and Part 4 covers adding personalization support with profiles.&amp;nbsp; You can find the entire series on MSDN here:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnaspp/html/ASPMemManSec.asp?frame=true" target="_blank"&gt;ASP.NET 2.0 Member/Role Management, Part 1: Security and Configuration Overview&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnaspp/html/ASP2memroleman.asp?frame=true" target="_blank"&gt;ASP.NET 2.0 Member/Role Management, Part 2: Implementation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnaspp/html/membershipeditoratlas.asp?frame=true" target="_blank"&gt;ASP.NET 2.0 Member/Role Management, Part 3: AJAX Enhancements with Microsoft Atlas&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnaspp/html/membershipeditorwithprofile.asp?frame=true" target="_blank"&gt;ASP.NET 2.0 Member/Role Management, Part 4: Adding Personalization with Profiles to the ObjectDataSource&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For more ASP.NET 2.0 Security Resources, please also check out my &lt;a href="http://weblogs.asp.net/scottgu/archive/2006/02/24/ASP.NET-2.0-Membership_2C00_-Roles_2C00_-Forms-Authentication_2C00_-and-Security-Resources-.aspx" target="_blank"&gt;ASP.NET 2.0 Security Resources Page&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Hope this helps,&lt;/p&gt;&lt;p&gt;Scott&lt;/p&gt;&lt;p&gt;P.S. IIS 7.0 includes built-in support within its GUI Admin tool for ASP.NET 2.0 Membership and Role Management -- making both local and remote management of sites super easy.&amp;nbsp; It will work with any custom provider you&amp;#39;ve built (so it is not limited to only working with the built-in ones).&amp;nbsp; It also does all of its remote management using HTTP based web-services -- which means it can work through firewalls as well as in shared hosting environments.&amp;nbsp; I&amp;#39;ll post some screen-shots of this in the near future showing it off (it is pretty darn cool).&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/font&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=458844" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category></item><item><title>Recipe: Enabling Windows Authentication within an Intranet ASP.NET Web application</title><link>http://weblogs.asp.net/scottgu/archive/2006/07/12/Recipe_3A00_-Enabling-Windows-Authentication-within-an-Intranet-ASP.NET-Web-application.aspx</link><pubDate>Wed, 12 Jul 2006 16:46:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:457088</guid><dc:creator>ScottGu</dc:creator><slash:comments>104</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=457088</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2006/07/12/Recipe_3A00_-Enabling-Windows-Authentication-within-an-Intranet-ASP.NET-Web-application.aspx#comments</comments><description>&lt;font face="arial" size="2"&gt;&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;You are building an Intranet web application for your organization, and you want to authenticate the users visiting your site.&amp;nbsp; Specifically, you want to ensure that they are logged in using a valid Windows account on the network, and you want to be able to retrieve each incoming user&amp;#39;s Windows account name and Windows group membership within your application code on the server.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Discussion:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Authentication&lt;/em&gt; is the process of identifying and validating the identity of a client accessing an application.&amp;nbsp; Put more simply -- it is the process of identifying &amp;ldquo;who&amp;rdquo; the end-user is when they visit a website.&amp;nbsp; &lt;/p&gt;&lt;p&gt;Authentication is typically used in combination with &lt;em&gt;Authorization&lt;/em&gt; -- which is the process of figuring out whether the authenticated user has permissions to access a particular page/resource or to perform some action.&amp;nbsp; For example, when an end-user in a browser tries to access a page, ASP.NET might authenticate the user as &amp;ldquo;Scott&amp;rdquo;, and would then run through the configured authorization rules for the requested page to figure out whether &amp;ldquo;Scott&amp;rdquo; has permission to access it.&lt;/p&gt;&lt;p&gt;ASP.NET supports multiple ways to authenticate browser users visiting a web application, and implements a flexible set of ways to authorize which permissions they have within the application.&lt;/p&gt;&lt;p&gt;For Internet web applications, the most common authentication scenario to use it called Forms Authentication.&amp;nbsp; Forms Authentication enables a developer to provide a standard HTML login form within their application, and then validate the username/password an end-user submits against a database or other credential store.&amp;nbsp; Assuming the username/password combination is correct, the developer can then ask ASP.NET to issue an encrypted HTTP cookie to identify and track the user.&lt;/p&gt;&lt;p&gt;For Intranet web applications, the most common authentication scenario to use is called Windows Authentication.&amp;nbsp; Windows Authentication avoids the need to create a login form within an application, and does not require end-users to manually enter their username/password credentials to login to the application.&amp;nbsp; Instead, ASP.NET and IIS can automatically retrieve and validate the Windows username of the end-user visiting the site in a secure way.&amp;nbsp; The benefit of this approach is that it improves the end-user customer experience since users don&amp;rsquo;t have to re-type their passwords, and/or maintain separate accounts.&amp;nbsp; It also allows companies to re-use a common security identity system across their entire corporate networks (Windows clients, servers, file-shares, printers, and web apps).&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;To enable Windows Authentication within an ASP.NET Application, you should make sure that you have &amp;ldquo;Integrated Windows Authentication&amp;rdquo; (formerly called NTLM authentication) enabled within IIS for the application you are building.&amp;nbsp; &lt;br /&gt;&amp;nbsp;&lt;br /&gt;You should then add a web.config file to the root directory of your ASP.NET application that contains an &amp;lt;authentication&amp;gt; section which sets the mode to &amp;ldquo;Windows&amp;rdquo;.&amp;nbsp; &lt;/p&gt;&lt;p&gt;You should also then add an &amp;lt;authorization&amp;gt; section to the same web.config file that denies access to &amp;ldquo;anonymous&amp;rdquo; users visiting the site.&amp;nbsp; This will force ASP.NET to always authenticate the incoming browser user using Windows Authentication &amp;ndash; and ensure that from within code on the server you can always access the username and Windows group membership of the incoming user.&lt;/p&gt;&lt;p&gt;The below web.config file demonstrates how to configure both steps described above:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&amp;nbsp;&amp;lt;configuration&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;system.web&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;authentication mode=&amp;quot;Windows&amp;quot; /&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;authorization&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;deny users=&amp;quot;?&amp;quot;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/authorization&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/system.web&amp;gt;&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Note that the &amp;lt;deny users=&amp;rdquo;?&amp;rdquo;/&amp;gt; directive within the &amp;lt;authorization&amp;gt; section above is what tells ASP.NET to deny access to the application to all &amp;ldquo;anonymous&amp;rdquo; users to the site (the &amp;ldquo;?&amp;rdquo; character means anonymous user).&amp;nbsp; This forces Windows to authenticate the user, and ensures that the username is always available from code on the server.&lt;/p&gt;&lt;p&gt;&lt;u&gt;Obtaining the Logged-in Username via Code&lt;/u&gt;&lt;/p&gt;&lt;p&gt;Once you follow the above configuration steps, you can easily access the logged-in username and role/group mappings for the authenticated user within ASP.NET.&amp;nbsp; For example, you could use the code-snippet below within an ASP.NET page to easily obtain the username of the visiting user:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Dim username As String&lt;br /&gt;username = User.Identity.Name&amp;nbsp;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The code-snippet above works because there is a &amp;ldquo;User&amp;rdquo; property built-in to all ASP.NET pages and user-controls.&amp;nbsp; If you want to gain access to this user data from within a regular class or business object (which doesn&amp;rsquo;t have this property provided), you can write code like below to achieve the same result:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Dim User As System.Security.Principal.IPrincipal&lt;br /&gt;User = System.Web.HttpContext.Current.User&lt;/p&gt;&lt;p&gt;Dim username As String&lt;br /&gt;username = User.Identity.Name&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The code above obtains the User IPrincipal object for the current request by accessing it via the static HttpContext.Current property that ASP.NET provides (this in turn uses call-context to retrieve it from the active ASP.NET worker thread).&amp;nbsp; This avoids you having to pass this User object into your business classes directly, and instead allows you to access the User object from anywhere in the application. &lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;u&gt;Outputting the Logged-in Username on a Page&lt;/u&gt;&lt;/p&gt;&lt;p&gt;You can use the username string we retrieved above to programmatically output the username to a page however you want.&amp;nbsp; For example, you could easily add an &amp;lt;asp:label&amp;gt; control to the page and write code like so to set it:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Label1.Text = &amp;quot;Welcome &amp;quot; &amp;amp; User.Identity.Name&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;ASP.NET 2.0 also ships with a built-in &amp;lt;asp:LoginName&amp;gt; control that you can use to declaratively output the user-name to the page:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&amp;lt;asp:LoginName ID=&amp;quot;LoginName1&amp;quot; FormatString=&amp;quot;Welcome {0}!&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This control provides an easy way to display the username within the application without having to write any code at all (note the use of the &amp;ldquo;FormatString&amp;rdquo; property on the control above &amp;ndash; which allows you to easily specify a text mask to use with it).&lt;/p&gt;&lt;p&gt;&lt;u&gt;Looking up Role/Group information for a User&lt;/u&gt;&lt;/p&gt;&lt;p&gt;ASP.NET provides a useful &amp;ldquo;Role Management&amp;rdquo; capability, which allows developers to map users into logical &amp;ldquo;Roles&amp;rdquo; that can then be used to better control end-user capabilities and authorization access.&amp;nbsp; For example, as a developer I could create a role called &amp;ldquo;managers&amp;rdquo; for my web application, and then limit access to portions of the site to only those users within the &amp;ldquo;managers&amp;rdquo; role (note: I will be posting additional recipes in the future that discuss how to fully use the Role Management authorization and capabilities features more).&lt;/p&gt;&lt;p&gt;When using Windows Authentication, ASP.NET allows developers to create and populate roles from multiple sources.&amp;nbsp; For example, a developer could setup the built-in ASP.NET 2.0 SqlRoleProvider to map Windows users to custom application roles that are store within a database.&amp;nbsp; This approach is very useful for scenarios where there might be application-specific role mappings that don&amp;rsquo;t make sense to push into a centralized Active Directory tree/store.&lt;/p&gt;&lt;p&gt;ASP.NET also makes it easy to access central Windows and Active Directory group mappings from within an application as well.&amp;nbsp; For example, if there is a Windows group on the Active Directory network called &amp;ldquo;DOMAIN\managers&amp;rdquo;, an ASP.NET application could lookup whether the current Windows authenticated user visiting the ASP.NET site belongs to this group by writing code like this:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;If User.IsInRole(&amp;quot;DOMAIN\managers&amp;quot;) Then&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp; Label1.Text = User.Identity.Name &amp;amp; &amp;quot; is a manager&amp;quot;&lt;br /&gt;Else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Label1.Text = User.Identity.Name &amp;amp; &amp;quot; is not a manager&amp;quot;&lt;br /&gt;End If&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Note that the role/group look-up is done via the &amp;ldquo;User.IsInRole(rolename)&amp;rdquo; method that is a peer of the User.Identity.Name property.&amp;nbsp; &lt;/p&gt;&lt;p&gt;&lt;u&gt;Next Steps&lt;/u&gt;&lt;/p&gt;&lt;p&gt;Once you understand the basics above, you know how to authenticate and identify Windows users visiting your Intranet application, as well as to lookup what Windows groups and roles they belong to.&lt;/p&gt;&lt;p&gt;In a future Recipe we&amp;rsquo;ll walkthrough more advanced role-management scenarios, and also discuss ways to authorize and restrict access and capabilities within an ASP.NET application based on the authenticated user&amp;rsquo;s authorization rights.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Additional Discussion:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;bull;&amp;nbsp;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/02/24/438953.aspx" target="_blank"&gt;Links to Tons of ASP.NET Security Content&lt;/a&gt;&lt;br /&gt;&amp;bull;&amp;nbsp;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/paght000025.asp" target="_blank"&gt;How To: Use Windows Authentication in ASP.NET 2.0&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Hope this helps,&lt;/p&gt;&lt;p&gt;Scott&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/font&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=457088" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category></item><item><title>Tip/Trick: Gathering Custom User Registration Information</title><link>http://weblogs.asp.net/scottgu/archive/2006/07/05/Tip_2F00_Trick_3A00_-Gathering-Custom-User-Registration-Information.aspx</link><pubDate>Thu, 06 Jul 2006 04:54:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:455682</guid><dc:creator>ScottGu</dc:creator><slash:comments>25</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=455682</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2006/07/05/Tip_2F00_Trick_3A00_-Gathering-Custom-User-Registration-Information.aspx#comments</comments><description>&lt;P&gt;&lt;STRONG&gt;&lt;FONT face=Arial size=2&gt;Problem&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;You are building a web-site that allows customers to register new users on the site.&amp;nbsp; As part of the registration process, you naturally want to allow them to create a username and password.&amp;nbsp; You also want them to enter additional personalization/registration data like their address, zipcode, gender, age, etc. and associate it with the newly created account.&amp;nbsp; You want to create an intuitive wizard-like navigation UI that enables customers to easily manage this workflow.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT face=Arial size=2&gt;Solution&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;ASP.NET 2.0 now provides a built-in control -- &amp;lt;asp:createuserwizard&amp;gt; -- that provides developers with an easy way to create user registration workflows for their site.&amp;nbsp; The &amp;lt;asp:createuserwizard&amp;gt; control provides built-in UI to enable an end-user to choose a username and password.&amp;nbsp; The &amp;lt;asp:createuserwizard&amp;gt; control also allows developers to specify additional "custom steps" of information to gather.&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;These custom steps can be defined using additional wizardstep templates defined&amp;nbsp;within the &amp;lt;asp:createuserwizard&amp;gt; control itself -- and so can contain any custom UI the developer wants.&amp;nbsp; &lt;/FONT&gt;&lt;FONT face=Arial size=2&gt;For example:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;&amp;lt;asp:WizardStep ID="CreateUserWizardStep0" runat="server"&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;div class="title"&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Billing Information&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;div class="address"&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;span&amp;gt;Billing Address:&amp;lt;/span&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;asp:TextBox ID="BillingAddress" MaxLength="50" runat="server"&amp;nbsp;&amp;nbsp;/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;asp:RequiredFieldValidator&amp;nbsp;ControlToValidate="BillingAddress" ErrorMessage="Address required!"&amp;nbsp;runat="server"/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;&lt;BR&gt;&amp;lt;/asp:WizardStep&amp;gt;&lt;/FONT&gt; &lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;The CreateUserWizard control will then automatically add "next"/"previous" navigation UI to enable an end-user to skip forward and back throughout the registration process.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;The CreateUserWizard control exposes a "CreatedUser" event that you can handle within your page to add logic to retrieve the information collected within the various WizardSteps, and store it within whatever database or profile store you want.&amp;nbsp; This event fires &lt;EM&gt;after&lt;/EM&gt; the user has been created within the ASP.NET Membership system.&amp;nbsp; However, the user is not yet logged into the ASP.NET site at this point (they won't be logged in until the page redisplays).&amp;nbsp; So to obtain the username of the newly created username you should access the &lt;EM&gt;CreateUserWizard.UserName&lt;/EM&gt; property.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;For example:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;Sub CreateUserWizard1_CreatedUser(Sender as Object, E as EventArgs) Handles CreateUserWizard.CreatedUser&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;FONT color=#ff0000&gt;' Obtain a reference to the "BillingAddress" textbox in the first step of the wizard&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Dim BillingAddress as TextBox&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;BillingAddress = CreateUserWizardStep0.ContentTemplateContainer.FindControl("BillingAddress")&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=1&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&lt;FONT color=#ff0000 size=2&gt;' Todo: Store the BillingAddress.Text value in a database or profile store&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;End Sub&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Two possible places you could perist this custom user&amp;nbsp;information are:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P style="MARGIN-RIGHT: 0px"&gt;&lt;FONT face=Arial size=2&gt;1) Within&amp;nbsp;a custom database table that you create and define.&amp;nbsp; You could replace the above "todo" statement in the CreatedUser event handler to insert this data into the database table using whatever data API you prefer (for example: ADO.NET or a &lt;A href="http://www.asp.net/learn/dataaccess/default.aspx?tabid=63"&gt;Strongly Typed Table Adapter&lt;/A&gt;).&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN-RIGHT: 0px"&gt;&lt;FONT face=Arial size=2&gt;2) Within the new ASP.NET 2.0 Profile system.&amp;nbsp; The ASP.NET Profile system provides a way to automatically persist additional properties/values about a user in a persistent store, and provides a strongly typed API that enables you to easly set/retrieve them (so for example you could just write Profile.BillingAddress to access the value).&amp;nbsp; The ASP.NET Profile system is by default mapped against an XML blob-like column within a database (which makes it easy to setup).&amp;nbsp; Alternatively, you can use the &lt;A href="http://weblogs.asp.net/scottgu/archive/2006/01/10/435038.aspx"&gt;ASP.NET SQL Table Profile Provider&lt;/A&gt; to map the Profile API against a schematized SQL table or set of SPROCs.&amp;nbsp; This gives you the nice strongly typed Profile API against a regular SQL table (which makes data-mining easier).&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P style="MARGIN-RIGHT: 0px"&gt;&lt;FONT face=Arial size=2&gt;To learn more about how to use the &amp;lt;asp:createuserwizard&amp;gt; control and download sample&amp;nbsp;code that uses it&amp;nbsp;I'd recommend reviewing these articles:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P style="MARGIN-RIGHT: 0px"&gt;&lt;FONT size=2&gt;&lt;A href="http://aspnet.4guysfromrolla.com/articles/070506-1.aspx"&gt;&lt;FONT face=Arial&gt;Customizing the CreateUserWizard Control&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Arial&gt;: This article was published in July of 2006, and provides a good walkthrough of the customization capabilities of the CreateUserWizard control, and how to store custom user properties directly within a database.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN-RIGHT: 0px"&gt;&lt;FONT size=2&gt;&lt;A href="http://weblogs.asp.net/scottgu/archive/2005/10/18/427754.aspx"&gt;&lt;FONT face=Arial&gt;How to add a Login, Roles, and Profile system to an ASP.NET 2.0 app in 24 lines of code&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Arial&gt;: This is a sample I put together towards the end of 2005 that shows how to integrate these three features in ASP.NET 2.0 to create a custom registration and profile management system.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN-RIGHT: 0px"&gt;&lt;FONT face=Arial size=2&gt;&lt;A href="http://www.asp.net/QuickStart/aspnet/doc/ctrlref/login/createuserwizard.aspx"&gt;CreateUserWizard Samples within the ASP.NET QuickStart tutorials:&lt;/A&gt; This page provides a number of samples (in both VB and C#) that you can use to understand how to use the CreateUserWizard control better.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN-RIGHT: 0px"&gt;&lt;FONT size=2&gt;&lt;A href="http://odetocode.com/Articles/440.aspx"&gt;&lt;FONT face=Arial&gt;Profiles in ASP.NET 2.0:&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Arial&gt; K. Scott Allen posted this nice article which does a good job providing an overview of the new ASP.NET 2.0 Profile API.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN-RIGHT: 0px"&gt;&lt;FONT face=Arial size=2&gt;&lt;A href="http://weblogs.asp.net/scottgu/archive/2006/02/24/438953.aspx"&gt;ASP.NET 2.0 Membership, Roles, Forms Authentication and Security Resources&lt;/A&gt;: This blog post of mine contains a ton of ASP.NET security informationa and useful links.&amp;nbsp; I'd recommend reviewing it to explore more about ASP.NET security.&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&lt;STRONG&gt;Credits&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&lt;A href="http://www.erichpeterson.com/"&gt;Erich Peterson&lt;/A&gt; and &lt;A href="http://odetocode.com/default.aspx"&gt;K. Scott Allen&lt;/A&gt; for the nice articles I listed above.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Hope this helps,&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Scott&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=455682" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category></item><item><title>Free Patterns and Practices Guidance Explorer for ASP.NET and .NET</title><link>http://weblogs.asp.net/scottgu/archive/2006/06/29/Free-Patterns-and-Practices-Guidance-Explorer-for-ASP.NET-and-.NET.aspx</link><pubDate>Fri, 30 Jun 2006 04:02:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:455260</guid><dc:creator>ScottGu</dc:creator><slash:comments>25</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/scottgu/rsscomments.aspx?PostID=455260</wfw:commentRss><comments>http://weblogs.asp.net/scottgu/archive/2006/06/29/Free-Patterns-and-Practices-Guidance-Explorer-for-ASP.NET-and-.NET.aspx#comments</comments><description>&lt;P&gt;&lt;FONT face=Arial size=2&gt;&lt;A href="http://blogs.msdn.com/jmeier/"&gt;JD Meier&lt;/A&gt; from the &lt;A href="http://msdn.microsoft.com/practices/"&gt;Prescriptive Architecture Guidance Group&lt;/A&gt; (aka PAG) at Microsoft stopped by my office this morning to show me the new Guidance Explorer tool he has been working on.&amp;nbsp; This is a cool WinForms client application that aggregates PAG guidance and suggestions, and allows you to search and sort across it.&amp;nbsp; This makes it ideal for quickly reviewing checklists of suggestions for ASP.NET projects.&amp;nbsp; Each guidance rule covers why it should be followed, and includes instructions on how to implement it.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;(Note: Click the screen-shots to enlage them)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&lt;A href="http://www.scottgu.com/blogposts/guidance/guidance.png"&gt;&lt;IMG src="http://www.scottgu.com/blogposts/guidance/guidance.png" width=700&gt; &lt;/A&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;A nice feature the tool provides is the ability to create and save&amp;nbsp;"custom views" of just the guidance you care about.&amp;nbsp; For example, in the screen-shot below I created a new custom view called "Scott Team" and then dragged/dropped a subset of the guidelines/suggestions I cared about into it:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&lt;A href="http://www.scottgu.com/blogposts/guidance/pic2.png"&gt;&lt;IMG src="http://www.scottgu.com/blogposts/guidance/pic2.png" width=700&gt;&lt;/A&gt; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Even better, you can optionally right-click on either&amp;nbsp;a guideline or a view made up of guidelines and export them to either a word document or html file:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&lt;IMG src="http://www.scottgu.com/blogposts/guidance/pic3.png"&gt; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;You can learn more about the tool and &lt;A href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=bb9aecfe-56ba-4ca9-8127-44e551b90962"&gt;download it for free here&lt;/A&gt; (the download location is in the bottom right of the page).&amp;nbsp; There is also a Wiki on Channel9 with more information &lt;A href="http://channel9.msdn.com/wiki/default.aspx/GuidanceLibrary.GuidanceExplorer"&gt;here&lt;/A&gt;, and JD has a great blog to subscribe to &lt;A href="http://blogs.msdn.com/jmeier/"&gt;here&lt;/A&gt;. The plan is to continually update the tool with additional guidance rules and checklists over the next few months (they've been doing 3-4 updates a month lately).&amp;nbsp; I definitely recommend checking it out.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Hope this helps,&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Scott&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=455260" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/scottgu/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/.NET/default.aspx">.NET</category><category domain="http://weblogs.asp.net/scottgu/archive/tags/Security/default.aspx">Security</category></item></channel></rss>