| ProfileI may have joined the wr...BlogLists | Help |
|
June 30 Moving daySusan Bradley has been kind enough to make some room for me over at MSMVPS.com, so this blog is finally moving to a spot where it won't be necessary to sign in to leave comments. The new blog is at http://msmvps.com/blogs/calinoiu/. The RSS and Atom feeds are at http://msmvps.com/blogs/calinoiu/rss.aspx and http://msmvps.com/blogs/calinoiu/atom.aspx, respectively. I'm closing the comments on this blog, but I've copied all existing posts to the new blog, so please feel free to comment on the old posts over there if you happen to feel the urge... June 19 New version (1.0.1.12) of Bordecal.ImportsSorter availableThere's a new version of the Bordecal.ImportsSorter add-in available for download. This new version allows shortcut keys to be permanently assigned to the configuration and/or sorting menu items via VStudio options. The hashes for the new MSI file are: MD5: f89f3c1bfa2a40adbb67315de8fef148 SHA1: c54803ba3392ca68ca29fd4dc9b4b359606f46c7 June 13 What's wrong with ASP.NET? HTML encodingThe problemBack when ASP.NET was first introduced, I had pretty high hopes that the new controls would offer support for automatic HTML encoding. Unfortunately, there was very little of this, and most of it was more than a bit lukewarm (more on this later). In some ways, things have improved a bit in v. 2.0, but they're considerably worse in others. Before you read any further, you might want to ask yourself which ASP.NET controls perform HTML encoding for you and under what circumstances this is done. If the answer doesn't leap to mind, you've perhaps got a first inkling that there might be a little problem with API consistency and/or the documentation. Then again, maybe you've never worried about HTML encoding in your web applications, in which case I'd strongly recommend that you read up on HTML injection and cross-site scripting. A good starting point might be CERT Advisory CA-2000-02. We'll look at which controls perform HTML encoding soon. First, we're going to need to nail down some conceptual stuff because not all encoding is created equal. You may already be aware that HTML, URLs, and client-side script use different encodings. For the sake of simplicity, the remainder of this post will refer mainly to HTML encoding, although the other two forms of encoding do merit consideration as well. There is more than one flavour of HTML encoding, even within ASP.NET. The first is exposed via the System.Web.HttpUtility.HtmlEncode methods. These encode the characters >, <, &, ", as well as any characters with codes between 160 and 255, inclusive. The other main encoding flavour used by ASP.NET is "attribute" encoding, which is exposed via the System.Web.HttpUtility.HtmlAttributeEncode methods. In ASP.NET 1.1., these encode the & and " characters only. In ASP.NET 2.0, these encode the characters <, &, and ". Attribute encoding ought to be a superset of full HTML encoding that also encodes the single quote character in case that's what happens to be wrapping the attribute. However, as you may have noticed from the above, the ASP.NET version of attribute encoding is even wimpier than its full encoding brother. To make matters worse, the full HTML encoding implemented by ASP.NET is no great shakes in the first place. Security isn't the only reason for HTML encoding, and failure to encode everything outside the low ASCII range can impact on page readability when client browsers don't apply the correct code page (which happens more often than you might think, whether it's the client's or the server's fault). Now that we know what kinds of HTML encoding are available in ASP.NET, let's take a look at the encoding support offered by the built-in ASP.NET controls. The following table covers some of the more commonly used controls and properties. (There are, of course, many other controls and properties that one might wish to see encoded, but I've tried to keep the list down to things that most folks are likely to use reasonably frequently.)
Assuming you've actually taken the time to read the above, you might have noticed that there are five basic patterns of encoding usage:
If this strikes you as perhaps a wee bit inconsistent, you wouldn't be alone. Wouldn't it be great to see a consistent approach that telegraphs well and acts as a pit of success? If all the controls performed HTML encoding by default but allowed overriding when necessary (preferably via a single approach), the vast majority of developers writing for ASP.NET would end up generating a more secure, more reliable applications with considerably less effort. WorkaroundsWhile we're all waiting around for the ASP.NET team to eventually provide reasonable built-in support for HTML encoding, what can we do to ensure that our apps are both protected from HTML injection and character mis-rendering? A good starting point would be to fully encode all data (i.e.: anything not 100% known at compile time, and even some stuff that is) that will be pushed to the client browser. Unfortunately, as was already mentioned above, the built-in encoding scheme leaves a little something to be desired. Luckily, the ACE team folks at Microsoft have been working on a couple of tools that take a more robust approach to HTML (and URL and script) encoding. Rather than blacklisting a fixed set of potentially problematic characters for encoding, they whitelist a set of known safe characters (low ASCII a-z, A-Z, 0-9, space, period, comma, dash, and underscore for HTML encoding) and encode everything else. This quite nicely takes care of both security and appearance issues, and you may wish to seriously consider using this approach rather than calling System.Web.HttpUtility.HtmlEncode to perform your HTML encoding. Regardless of which HTML encoding approach you select, you're quickly going to run into a bit of trouble with double encoding if you simply start assigning pre-encoded text to control properties (e.g.: someTextBox.Text = HttpUtility.HtmlEncode(someString)). When dealing with malicious input, this is pretty much a non-issue. However, not all data that ought to be encoded is malicious, and you usually wouldn't want users seeing stuff like a > b rather than a > b. Unfortunately, if we want to avoid double encoding in the set of controls that perform non-overrideable encoding (including attribute encoding), we need to use custom controls. To make matters worse, it can require rather a lot of work to subclass most of the controls in order to override the encoding behaviour. In quite a few cases, simply starting from scratch would probably make more sense than trying to subclass the built-in controls. Also, even for those controls where double encoding wouldn't be an issue (e.g.: Label, CheckBox), it's probably worth considering using custom controls anyway since the pain of authoring the custom control isn't likely to outweigh the cumulative effort of all the manual encoding calls you might make across all your projects. Don't like these workarounds? Maybe it's time to start complaining... June 09 What’s wrong with ASP.NET? ValidationASP.NET introduced a fancy new user input validation framework that, at least at first glance, appears to be a great advance over the complete lack of built-in validation support in ASP.OLD. Declarative validation is certainly wonderful stuff, and getting client-side validation with no additional effort (at least if your clients are using supported browsers) isn’t too shabby either. Overall, using the built-in validation controls certainly seems like a good idea, particularly for those folks who wouldn’t be performing any validation otherwise because of the amount of work involved. But what about those of us who had been performing validation all along? Do the ASP.NET validation controls really offer equivalent protection to our former "manual" validation? Unfortunately, for many of us, the answer is probably "no". The main problem lies with the validation paradigm chosen for ASP.NET, which has the following properties:
So what’s wrong with that, you ask? Well, each of the validation controls needs to re-read the target control value, as does the code that will ultimately process that value. To make the problem a bit more concrete, let’s look at the example of validating a birth date provided via a text box:
In the above example, each validation control reads the text box value independently, which means that they cannot build upon parsing and restriction steps performed by the other validators. In addition, when our code needs to process the birth date, it must go back to the text box and read the string value again. That mean that there are at least 5 reads and 4 separate parsing operations from the original text box value, each of which represents an opportunity to parse inconsistently with respect to culture and/or format. In addition, there’s no guarantee that each of those 5 reads is even accessing the same value since it’s possible for the text box’s Text property to be altered between the reads (even if this is somewhat unlikely in an ASP.NET app). How can we address this problem? There are plenty of workarounds, including using only custom validation controls, but that means quite a bit more work for developers. A much more reliable approach would involve reading the "raw" value from the text box only once. It would then be passed from one validator to another in a pre-defined order and would only require a single parsing. In the birth date example, the validator at step 2 would output a strongly typed DateTime value (assuming, of course, that step 2 validation passed), and that’s the value that would be passed to the validator at step 3. The output from step 5 would be the value that our code would read, rather than going back to the text box to read its Text property. It’s entirely feasible to develop such a framework, but it’s also quite a bit of a lot of work, particularly when one considers addition of appropriate design-time support. It’s obviously not the sort of thing on which most shops would want their developers spending time. Unfortunately, it’s also not the sort of thing that many shops would be willing to pay for as a third-party product, particularly given that most developers probably perceive themselves as getting by just fine with the existing ASP.NET validation controls. On the other hand, it would probably be a reasonably small project on the Microsoft scale of things, and I suspect that I’m not the only one who would sleep better if the built-in tools would help the Morts of this world develop more reliable and secure applications out of the box, particularly given that most of us use applications built on those tools sooner on a more or less regular basis. What’s wrong with ASP.NET?For quite some time now, I’ve been harbouring an increasing bit of frustration with ASP.NET. Overall, I like the platform, and I think that it’s a great advance over ASP.OLD. Unfortunately, there are a few areas in which I can’t help but feel that the design team missed the boat by just a wee bit too much, and compensating for these lacunae can mean a ridiculous amount of work for the individual developer. There are three main areas that have been grating on my nerves of late:
I’d love to see the ASP.NET team address fundamentals like these in upcoming versions, but new features generally garner considerably more interest amongst users than fixing things that very few people ever realized were broken. In an attempt to perhaps rouse a bit of interest in the latter, I’m starting a short series of posts on the above topics, starting with What’s wrong with ASP.NET? Validation. June 02 New version of ImportsSorter add-in availableThere's a new version of the Bordecal.ImportsSorter add-in available for download. The only change is a fix for a bug that raised its ugly head when the shortcut menu was polled by another add-in. The hashes for the new MSI file are: MD5: b91a7abde826173a0d7c9f5e05126b35 SHA1: 1b54e49189a921a07eecca82749860b6f9e41d7a February 18 Hopping databases from the SAFE SQLCLR permission levelI've seen quite a few articles over the past few months that make the assumption that one can only connect to the hosting database from SQLCLR code running at the SAFE permission level. I can't seem to find any official MSDN documentation that would directly reinforce this misconception, so I'm guessing that it stems from the limitation of the SqlClientPermission at the SAFE level to only allow use of the following connection strings (with optional specification of the Type System Version parameter): context connection=trueor context connection=yes Unfortunately, the documentation for the SqlClientPermission.Add method is a wee bit ambiguous with respect to the effect of preventing arbitrary target database specifications in the connection string, and one might easily be led into believing that preventing use of the database parameter will prevent connections to unintended databases. However, while it will prevent mucking about with the connection string, that's not enough to prevent connecting to other databases. For starters, the SqlConnection object has a ChangeDatabase method that allows one to target another database after an initial connection has already been established.e.g.:1 using (SqlConnection connection = new SqlConnection(@"Data Source=(local);Initial Catalog=AllowedDB;Integrated Security=True"))
{
connection.Open();
connection.ChangeDatabase("ForbiddenDB");
using (SqlCommand command = connection.CreateCommand())
{
command.CommandType = CommandType.Text;
command.CommandText = "SELECT DB_NAME()";
Console.WriteLine((string)command.ExecuteScalar());
}
}
Now, one might argue that this is actually a bug, and that ChangeDatabase method ought to demand SqlClientPermission for the target database before making the switch. However, it's quite possible to bypass the SqlClient layer entirely and make the switch inside database code, so any additional protection at the SqlClient level would only provide a false sense of security and probably isn't worth implementing. The next approach invokes making a direct database context switch from T-SQL using the USE statement. e.g.: using (SqlConnection connection = new SqlConnection(@"Data Source=(local);Initial Catalog=AllowedDB;Integrated Security=True"))
{
connection.Open();
using (SqlCommand command = connection.CreateCommand())
{
command.CommandType = CommandType.Text;
command.CommandText = "USE ForbiddenDB";
command.ExecuteNonQuery();
command.CommandText = "SELECT DB_NAME()";
Console.WriteLine((string)command.ExecuteScalar());
}
}
Effectively, this means that SqlClientPermission provides no protection against using any particular database within a given SQL Server instance. You might guess that the SQLCLR might add some additional protection against database switching from within hosted code, but you'd be wrong. The above techniques work just as well against the SQLCLR context connection as they do against a plain, old vanilla connection as shown above. SAFE or not, SQLCLR assemblies can connect to any database in their host SQL Server instance assuming, of course, that user permissions also allow the connection. 1 The DB_NAME function, when called with no parameters, returns the name of the current database. If you haven't switched the context database, the function would be expected to return the name of the database against which the connection was originally established. January 07 Why is my application coughing up a SecurityException after my code stops running?Odd exceptions at odd timesIf you apply a PrincipalPermission attribute to a class in order to restrict the users and/or roles that are permitted to use the class, you may start seeing security exceptions like the following being thrown at unexpected times (like, say, when your application is quitting): System.Security.SecurityException was unhandled
Message="Request for principal permission failed."
Source="mscorlib"
StackTrace:
at System.Security.Permissions.PrincipalPermission.ThrowSecurityException()
at System.Security.Permissions.PrincipalPermission.Demand()
at System.Security.PermissionSet.DemandNonCAS()
at YourNamespace.YourClass.Finalize()
What's up with that?The basic gist of the above exception that the demand for your specified PrincipalPermission is failing when the finalizer for your class is invoked. If your class also happens to be disposable, and disposition suppresses its finalization, you might be tempted to believe that this problem occurs because the thread principal couldn't satisfy the original PrincipalPermission demand at construction. However, things are a wee bit more complicated than that... Finalization is triggered by the garbage collector and runs on a separate thread controlled by the garbage collector. This means that the principal that you set on your application's thread won't be applied to the thread on which an instance of your finalizable type gets finalized. Your PrincipalPermission demand will always fail at finalization, regardless of the thread principal set within your application. Another surprise might be that there's an object available for finalization at all if the PrincipalPermission demand fails when the constructor is invoked. What you actually end up with in such a case is a partially constructed instance of your type. This instance won't be available to the invoking code, so it won't be subject to disposition, but the garbage collector will still attempt to finalize it despite the fact that it isn't fully constructed. So what can I do about all this?The simple answer is you need to make it possible for the finalizer (and any other methods it calls) to run despite the fact that the finalizer thread cannot satisfy the class-level PrincipalPermission demand. You can do this by applying a PrincipalPermission attribute that allows unauthenticated callers to the finalizer (and any methods it calls). The C# form of this attribute would be: [PrincipalPermission(SecurityAction.Demand, Authenticated = false)] The VB form would be: <PrincipalPermission(SecurityAction.Demand, Authenticated:=False)> Obviously, if you're going to be removing the requirement for the class-level PrincipalPermission from the finalizer or any other methods, you should also ensure that these methods don't perform any actions that should require whatever user identity or role membership specified by the original PrincipalPermission. You may want to also consider applying the same PrincipalPermission reversal on any methods used for disposition, even if these are not invoked from your finalizer. (This would be a bit of an odd design choice in most cases, but if that's what you're using, you should be addressing the consequences.) The main reason for this is that disposition might not be invoked under the same principal as was in place at construction. As with finalization, you should ensure that your disposition methods don't perform any "high-privilege" actions if you do choose to reverse the PrincipalPermission requirement. If that was the simple answer...The good news is that the above approach is pretty much the only approach. It's reasonably clear-cut, and there's not much that you can do in terms of variation on the theme. The bad news is that, if you're running into this particular problem, chances are pretty good that you should perhaps be concerned about some of the finer details of finalization and disposition. If you're interested in learning more about these, I'd recommend reading Chris Brumme's blog entry on finalization. If you're implementing disposition as well as a finalizer, you should probably take a look at the recommended disposition pattern, and maybe even the whitepaper on .NET Framework Resource Management. December 04 Secure by de...what?Surprise!User instances are a new capability of SQL Server 2005 (Express edition only) that are supposedly intended to allow non-admins to attach database files without requiring additional permissions. This actually works just fine and, at first glance, it probably strikes most folks as a lovely least-privilege accomodation. The unfortunate bit that might not be immediately obvious to the casual user is that this is accomplished by granting the connecting user sysadmin privilege over his user instance. This means that every connection to a user instance is a connection running as sysadmin. So... What's so bad about connecting as sysadmin?If you're at all familiar with secure practices around database connectivity, you've probably heard that you should never connect under a sysadmin login unless you're connecting for the express purpose of performing administrative tasks. The main reason for this is that a sysadmin login has unlimited control over the SQL Server instance, as well as being able to "climb" out of the SQL Server instance via extended stored procedures (or hosted SQLCLR code, in the case of SQL Server 2005) to affect other machine resources. In other words, code running under a sysadmin login can fully control the SQL Server instance and can do anything on the machine or network that either the login account or the SQL Server service account can do. It's also possible to impersonate other Windows accounts when calling outside SQL Server, so the damage potential isn't necessarily limited by the privileges of the login and service account. Yikes! But, ummm... Yikes!Hmmm... Sounds like running user instances might be just a wee bit on the risky side, doesn't it? After a bit of a stumped initial reaction, the little voices in my head started evaluating the implementation against SD3+C ("secure by design, secure by default, secure in deployment, and communications") criteria, which is supposed to be an integral part of the Microsoft security development lifecycle. I can't help but feel that some less risky choices might have been made along the way, but perhaps that's just my paranoid nutbag side talking. You decide... Secure by design? The main goal of user instance mode seems to be allowing applications to attach database files even when running under a limited privilege user account. That's pretty necessary if you're going to, say, push user instance mode SQL Server Express as a replacement for Jet. That said, might some safer design choices have been made when choosing how to implement this requirement? This would allow even dbcreator membership to be revoked when it isn't actually needed, which could be the case if one were to configure the user instance template data files to pre-connect to a designated set of databases.
Secure by default? Well, it looks like someone did at least give this one the old college try. For example, regardless of the master instance setting, a user instance will have xp_cmdshell use disabled by default. Unfortunately, it's trivial to enable the option from within any application connected to a user instance since the user is running as a sysadmin, so this is essentially just a bit of cosmetic cover-up. Given the current design, the only real "secure by default" setting that I can see would be to deploy SQL Server Express with user instance mode disabled by default. Since most machines on which the Express edition will be installed will likely never need to run user instances, it's really rather disappointing that it's enabled by default in the first place. Then again, this is an obvious ease of use vs. security trade-off, and it's not exactly difficult to imagine the meeting at which the decision was made... Secure in deployment? There's little an administrator or user can do to make user instances more secure if they're enabled. There appears to be no information at all out there about the risks of their use, forget about guidance on "how to use it securely". We'll have to wait to see if updates will be easy to deploy, but updating all user instances on any given machine will certainly pose some potentially interesting challenges. Communications? Well, I guess we'll see... ;) Ouch! Band-aids, anyone?If you need to install the SQL Server Express edition and want to protect yourself against these risks, there are a few things you can do. For starters, unless you absolutely need user instances, disabling them would probably be a really good idea. This can be done by executing sp_configure against the master SQL Express instance on a machine as follows: sp_configure 'user instances enabled', '0' GO RECONFIGURE GO Developers who distribute SQL Server Express edition with their applications might also want to keep this in mind. If you don't use user instances in your application, you should probably disable them as part of the installation. Also, given the risks involved with running user instances, you might want to consider avoiding their use if at all possible. (BTW, if you've installed Visual Studio 2005 on your machine, there's a good chance that SQL Express edition was also installed, and you might want to take a little break from reading this in order to run off and disable user instances.) So, that's all fine and dandy if you don't need user instances at all. What happens if you really need to run an application that uses user instances? For starters, you might want to limit which users can create user instances. Unfortunately, as far as I know, the only way to do this at present would be to remove user permissions on the directory created for a user instance. In other words, for any user to whom you wish to deny user instances, you would need to create a %USERPROFILE%\Local Settings\Application Data\Microsoft\Microsoft SQL Server Data\SQLEXPRESS folder, then remove the user's NTFS permissions on the folder. Since this is a major pain in the caboose, as well as easy to miss doing for any given account, it's the sort of thing you might want to consider automating via a default login script or similar mechanism. BTW, if you do make this permission alteration, other processes such as backups may be affected, so you might want to do some pretty thorough testing before, say, pushing this sort of thing out to your entire domain... What about CAS permissions?Sorry, but CAS isn't going to help much here if you allow connections to a user instance. Code with any SqlClientPermission can do anything the connecting user is allowed to do via the SQL Server instance. When connecting to a remote instance (or even a local non-user instance), the user's capabilities are usually (or so one would hope!) constrained by their NTFS permissions, SQL Server permissions, and limitations imposed by the configuration of the SQL Server instance. However, running as sysadmin on a user instance, these contraints are mostly absent. If you grant any SqlClientPermission to managed code that permits connection to a user instance, you are effectively granting permission for that code to do anything the user can do. The end result for a malicious application is the same as if you had granted unrestricted CAS permissions (aka "full trust"). In other words, you shouldn't be granting SqlClientPermission that includes the possibility to connect to a user instance to any assembly unless you would happily grant unrestricted permissions as well. This means that granting unrestricted SqlClientPermission to any code (other than as part of a full trust grant) is a pretty horrible idea. Unfortunately, if you want to grant "almost unrestricted" SqlClientPermission that excludes the right to connect to user instances, the CAS permission configuration UIs won't be of much help. Instead, you'll need to define the permission "manually". The XML definition for such a permission might look like this (watch out for fakey angle brackets if you copy and paste): ‹IPermission class="System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" AllowBlankPassword="True"› ‹add KeyRestrictions="User Instance=;" KeyRestrictionBehavior="PreventUsage" /› ‹/IPermission› If you want to grant additional permissions to a network-sourced assembly so that it can connect to a SQL Server instance running any server on your network, I'd recommend you use something like the above permission rather than an unrestricted SqlClientPermission grant. Otherwise, you might unwittingly be granting that assembly essentially unrestricted permissions over the machine on which it's executing via code run within a user instance. Wrapping things up...In my opinion, SQL Express user instances just plain don't meet the SD3+C bar, and disabling them is probably the best way for most of us to protect ourselves against the risks they introduce. Then again, I am a something of a paranoid nutbag, so your mileage may vary greatly... ;) New version of Bordecal.ImportsSorter add-in availableOnce I actually started using my imports sorter add-in from the Larkware 2005 Developer Tool Programming Contest on a semi-regular basis, there were a few things that started irritating the heck out of me (and were presumably worse for everyone else). Finally found a bit of time to fix and test things, and a new version is available for download here, with updated documentation here. The new stuff includes:
If you use the add-in and find a problem, just give me a shout at calinoiu@gmail.com... |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|