Beginning ASP.NET Security2

PART II: Securing Common ASP.NET Tasks

Chapter 7: Adding usernames and passwords

Authentication and Authorization

Discovering Your Own Identity

Adding Authentication in ASP.NET

Using Forms Authentication

Configuration Forms Authentication

Using SQL as a Membership Store

Creating Users

Examining How Users Are Stored

Configuring the Membership Settings

Creating Users Programmatically

Supporting Password Changes and Resets

Windows Authentication

Configuring IIS for Windows Authentication

Impersonation with Windows Authentication

If you want to pass the user’s identity to another system then you need to wrap the call in the follow code:

using (((WindowsIdentity)HttpContext.Current.User.Identity).Impersonate())

{

    // Perform database or network access here

}     

Authorization in ASP.NET

Examining <allow> and <deny>

Role-Based Authorization

Configuring Roles with Forms-Based Authentication

Using the Configuration Tools to Manage Roles

Managing Roles Programmatically

Managing Role Members Programmatically

Limiting Access to Files and Folders

Checking Users and Roles Programmatically

Securing Object References

A checklist for Authentication and Authorization

  • Do not roll your own unless you have to.—There are some cases where you may wish to develop own authentication and authorization functions, but doing so is fraught with potential mistakes. If you have an existing user database, then consider implementing the membership and roles provider models. This will enable you to use the standard methods to control access.
  • Encourage your uses to logout.—Persistent authentication can lead to CSRF attacks. For high-value systems encourage users to log out by providing a visible and consistent logout button and do not provide “Remember Me” functionality.
  • Always start with a deny access role.—Being specific in who you allow to access resources is safer than specifying who does not have access.
  • Be aware of the difference between ASP.NET and IIS authorization rules.—IIS authorization rules run against every resource. ASP.NET authorization rules will only protect resources mapped to a managed code handler.
  • If you use programmatic authorization checks to hide or display control, ensure those authorization checks run during execution of the underlying code.—If you show or hode user elements such as buttons based on roles or usernames, check again in any method bound to those buttons such as an OnClick() event.
  • If resources belong to a user check the current user before serving them.—If a resource such as a message is for a particular user then check the current user  has access to that resource.

Chapter 8: Securely accessing databases

Writing Bad Code: Demonstrating SQL Injection

Fixing the Vulnerability

More Security for SQL Server

Connecting Without Passwords

SQL Permissions

Adding a User to a Database

CREATE USER Olle FOR LOGIN Olle; 

Managing SQL Permissions

GRANT SELECT ON Example TO PUCK\Guest

DENY SELECT ON Example TO Olle

REVOKE SELECT ON Example TO Olle

GRANT EXECUTE ON GetLogins TO Olle

Groups and Roles

CREATE ROLE auditors AUTHORIZATION db_owner;  

EXEC sp_addrolemember 'auditors', 'PhilHa' 

GRANT EXECUTE ON ReadAuditLogin TO auditors   

Least Privilege Accounts

Using Views

SQL Express User Instances

Drawbacks of the VS Built-in Web Server

Dynamic SQL Stored Procedures

Wrong dynamic SQL stored procedures:

CREATE PROCEDURE search_orders @custId   nchar(5)     = NULL,

                               @shipTo nvarchar(40) = NULL AS

DECLARE @sql nvarchar(4000)

SELECT @sql = ' SELECT OrderID, OrderDate, CustomerID, ShipTo ' +

              ' FROM dbo.Orders WHERE 1 = 1 '

IF @custid IS NOT NULL

   SELECT @sql = @sql + ' AND custid LIKE ''' + @customerID + ''''

   IF @shipTo IS NOT NULL

   SELECT @sql = @sql + ' AND ShipTo LIKE ''' + @shipTo + ''''

EXEC(@sql)

Correct one:

CREATE PROCEDURE search_orders @custId   nchar(5) = NULL,

                               @shipTo nvarchar(40) = NULL AS

DECLARE @sql nvarchar(4000)

SELECT @sql = ' SELECT OrderID, OrderDate, CustomerID, ShipName ' +

              ' FROM dbo.Orders WHERE 1 = 1 '

IF @custid IS NOT NULL

   SELECT @sql = @sql + ' AND CustomerID LIKE @custId '

IF @shipTo IS NOT NULL

   SELECT @sql = @sql + ' AND ShipName LIKE @shipTo '

EXEC sp_executesql @sql, N'@custid nchar(5), @shipTo nvarchar(40)',

                   @custid, @shipTo 

Using SQL Encryption

Encrypting by Pass Phrase

SQL Symmetric Entryption

SQL Asymmetric Encryption

Calculting Hashes and HMACs in SQL

A Checklist for securely Accessing Databases

  • Never dynamically build SQL queries.—Dynamic queries are a vector for SQL injection.
  • Always use SQL parameters.—SQL parameters will automatically escape dangerous characters and help you void SQL injection.
  • Control access to your data.—If you can use stored procedures and SQL permissions to limit access to the underlying database. If you cannot use stored procedures, use updatable view to limit access to the underlying database. Stored procedures are not a panacea because they can, in turn, contain dynamic SQL themselves.

Chapter 9: Using the file system

Accessing Existing Files Safely

Making Static Files Secure

use Server.MapPath:

using System;

using System.IO;

public partial class getfile : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

        Response.Clear();

        string filename = 

            Path.GetFileName(Request.QueryString["filename"]);

            FileInfo file = new FileInfo(

              Server.MapPath(

                 Path.Combine("documents", filename)));

        Response.AddHeader("Content - Length", 

            file.Length.ToString());

        Response.ContentType = "text/plain";

        Response.WriteFile(file.FullName);

        Response.End(); 

    }

Checking That Your Application Can Access Files

using System;

using System.IO;

using System.Security;

using System.Security.Permissions;

public partial class getfile : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

        Response.Clear();

        string filename = Path.GetFileName(Request.QueryString["filename"]);

        string fullPath = Server.MapPath(

            Path.Combine(@"c:\inetpub\wroxStaticFiles\", ?lename));

        FileIOPermission accessPermission = 

            new FileIOPermission(FileIOPermissionAccess.Read, fullPath);

        try

        {

            accessPermission.Demand();

            FileInfo file = new FileInfo(

                Server.MapPath(

                    Path.Combine("documents", filename)));

            Response.AddHeader("Content-Length", file.Length.ToString());

            Response.WriteFile(file.FullName);

        }

        catch (SecurityException)

        {

            Response.Write("Access Denied");

        }

        

        Response.End();

    }

} 

Making a File Downloadable and Setting Its Name

You can use the Response headers to set the filename of the file being served by using the Content-Disposition header like so:

Response.AddHeader("Content-Disposition", "filename=" & filename);

Furthermore, you can use Content-Disposition to cause a download rather than rendering in the browser:

 Response.AddHeader("Content-Disposition", "attachment; filename=" & filename);

Adding Further Checks to File Access

Adding Role Checks

Anti-Leeching Checks

if (Request.UrlReferrer.Host != "mysite.example"  && 

    Request.UrlReferrer.Host != "www.mysite.example")

{

    Response.End();

}

else

{

    // Continue

} 

Remember that, like anything from the HTTPRequest, the referrer is untrusted input and could be be faked by an attacker. Futhermore, some privacy software strips the referrer from a request, and a direct access to a file via its full URI will also mean the referrer is blank. You should always serve the file if the referrer is blank.

Accessing Files on a Remote System

Creating Files Safely

Path.GetTempFileName() will generate a filename with a .TMP extension located in the system temporary directory, and create a zero length file. However, the number of temporary file is limited to 65535 files, so old files must be cleaned as quickly as possible.

User Path.GetRandomFileName() to generates a cryptographically strong random value that you can create a file or directory.

A quick and easy scheduler using the ASP.NET cache:

<%@ Application Language="C#" %> 

<script runat="server"> 

   private const string CleanUpTask = "appCleanFiles";

   private static CacheItemRemovedCallback OnCacheRemove = null;

   void Application_Start(object sender, EventArgs e) 

   {

       // code that runs on application startup

       AddTask(CleanUpTask, 60);

       

   }

   private void AddTask(string taskName, int frequency)

   {

       OnCacheRemove = this.CacheItemRemoved;

       HttpRuntime.Cache.Insert(taskName, frequency, null,

           DateTime.Now.AddSeconds(frequency), Cache.NoSlidingExpiration,

           CacheItemPriority.NotRemovable, OnCacheRemove);

   }

   public void CacheItemRemoved(string key, object value, 

        CacheItemRemovedReason reason)

   {

       switch (key)

       {

           case CleanUpTask:

               // Perform our cleanup here

               break;

       }

       

       // re-add our task so it recurs

       AddTask(key, Convert.ToInt32(value));

   }       

</script>    

Handling User Uploads

Using the File Upload Control

For safety, you should ignore any filename sent with the upload request. Instead, you should create a random filename and save the original filename against it. You can then use the original filename as part of a ContentDisposition header when you serve the file back to users.

Change the maximum request size:

<?xml version="1.0"?>

<configuration > 

   ....

    <system.web> 

      <httpRuntime

           executionTimeout = "90"

           maxRequestLength="4096" 

       /> 

       ....

    </system.web> 

   ....

</configuration>

WARNING: Increasing the maxRequestLength and executionTimeout properties may expose your application to a DOS attack. Experiment with your server configuration to discover the maximum values your hardware will support.

A Checklist for Securely Accessing Files

  • Truncate user specific file name and extract just the file name from any potential path.—Use the Path.GetFileName() to safely remove all directory information.
  • Serve content from a directory outside of your Web application.—If you must serve content from within your application path, then use Server.MapPath() to resolve directories. Server.MapPath() will stop any directory resolution from escaping out of the root of your application.
  • Use code access Secruity demands to ensure your application has the ability to access the file system.—Remember that .NET applications have their own permissions in addition to underlying file system permissions.
  • Create your own file names.—Use Path.GetRandomFileName() to generate filenames and directory names when you create files. This will avoid the overwriting of existing files, or any traps with reserved names and directory transversal attacks.
  • Limit the maximum request size and execution timeout for your application to prevent DOS attacks.—Never trust any input from file uploads. Generate your own filenames and use indirect object references to retrieve these files.

Chapter 10: Securing XML

Validating XML

Well-Formed XML

Valid XML

XML Parsers

Querying XML

Avoid XPath Injection

string xPath = 

    "string(//Account[UserName/text()=$username"+

    " and " +

    "Password/text()=$password]/UserName/text())"; 

   

// This could be performed in a constructor to avoid

// the CPU hit needed each time an expression is compiled.

XPathNavigator navigator =  xmlDocument.CreateNavigator();

XPathExpression expression = DynamicContext.Compile(xPath);

   

DynamicContext ctx = new DynamicContext();

ctx.AddVariable("username", username);

ctx.AddVariable("password", password);

expression.SetContext(ctx);

   

string account = Convert.ToString(navigator.Evaluate(expression));  

Securing XML Documents

Encrypting XML Documents

Using a Symmetric Encryption Key with XML

Using an Asymmetric Key Pair to Encrypt and Decrypt XML

Using an X509 Certificate to Encrypt and Decrypt XML

Signing XML Documents

A Checklist for XML

  • XML should be validated before trusting and using it.—Remember that the well-formed status of an XML document is not a guarantee of its validity.
  • Validate all XML against a strict schema.—Use local copies of XML schemas whenever possible. If you need to use external schemas, consider caching them with a caching resolver.
  • Choose and appropriate encryption method for your situation.—Generally, if your application needs to encrypt and decrypt the same data, choose a symmetric algorithm. If your application talks to an external system, choose an asymmetric algorithm.
  • Always use digital signatures if you need to ensure data has not changed.—Encryption is not enough when you cannot detect changes in data. Even unencrypted data may need a mechanism for detecting changes. Use digital signing to provide a security mechanism against unauthorized modification.

你可能感兴趣的:(Security)