DotNetNuke is a highly robust web-application framework that is ideally suited for a wide variety of purposes, from simple websites to enterprise applications. Associated with the framework is a team of security professionals who are dedicated to ensuring that third-party developers are able to create secure modules (and that the DotNetNuke framework itself is maximally secured against external threat). In this way, DotNetNuke developers are able to quickly leverage security services provided by the core framework, allowing for more rapid development and increased overall quality.
While in some cases these services serve merely to expose an easy-to-consume interface to already-existing .NET functionality (e.g. encryption and permissions), in many instances these services would not be available at the ASP.NET level without significant additional work (or by the consumption of an external library). Additionally, extensions which rely on core functionality are able to benefit from subsequent enhancements to the framework, typically without any modifications to the extension itself. Because of this, DotNetNuke developers are often able to design and deploy modules and extensions that are more secure, more quickly, and with less development effort expended.
DotNetNuke developers are often able to design and deploy modules and extensions that are more secure, more quickly, and with less development effort expended
Herein we review some of the security-related services that are offered by the core DotNetNuke framework and discuss their ability to defend against real-world threats.
Framework-Managed Authorization and Lifecycle
DotNetNuke handles much of the routine authorization and instantiation logic on behalf of a developer. When a module is installed, it may register one or more controls that require explicit permission to access. When the module is later added to a page, an authorized party associates the ability to view and edit that instance with one or more security roles. Thereafter DotNetNuke manages this association; users who are not a member of one of the authorized roles will not only be disallowed from utilizing the associated control, but the control itself will not even be instantiated by the framework. The fact that the control is neither instantiated nor added to the control hierarchy ensures that some forms of attacks are made more difficult, and, most saliently, moves the responsibility for authorization out of the hands of the module developer and into the framework (where it should be). Only in specific scenarios will a module developer need to implement additional authorization logic at all.
The DotNetNuke.Security.PortalSecurity Class
The PortalSecurity class contains a number of methods that may be leveraged by developers. In general, these methods may be categorized into groups that address input sanitization, encryption, privacy, and authorization. These methods are summarized in table 1. We explore each of these in more detail below.
| PortalSecurity Method |
Description |
| InputFilter |
Used to prevent malicious cross-site scripting (XSS) or SQL injection attacks. |
| Encrypt |
Encrypts a string given a key and value. |
| Decrypt |
Decrypts a string given a key and value. |
| CreateKey |
Creates a key of a given size using a cryptographically-strong algorithm. |
| ForceSecureConnection |
Requires that the current page be requested via the HTTPS protocol. |
| SignOut |
Deauthorizes a user from the ASP.NET forms authentication system and clears all DotNetNuke-related cookies. |
| ClearRoles |
Clears all cached role cookies associated with the current user. |
Table 1: The public methods of the DotNetNuke.Security.PortalSecurity class
PortalSecurity.InputFilter
By far the most commonly-used method by module developers, DotNetNuke offers an InputFilter method that is designed to aid in reducing some of the most common data sanitization issues an extension developer is likely to experience. A flag specifies which of the five filter types are performed; we explore the subtleties of these flags in turn.
FilterFlag.NoMarkup
When this flag is set, the text is returned HTML-encoded if and only if the source text contains one or more tags (i.e. elements with an opening and closing marker such as <tag>). This is by far the most secure filter with which to sanitize untrusted input, as it effectively fully mitigates the risk of malicious markup. Note that for data that are intended to be displayed as HTML (e.g. a forum post that by-design allows for limited markup), this method might not be suitable, as it will encode everything, including authorized markup.
Table 2 illustrates some of the transformations that are performed by this filter method.
| Input |
InputFilter(Input, FilterFlag.NoMarkup) |
| Regular Text |
Regular Text |
| Text with <Markup /> |
Text with <Markup /> |
| <Already Encoded Markup /> |
<Already Encoded Markup /> |
| Text without markup: 5 > 3 |
Text without markup: 5 > 3 |
Table 2: Some sample HTML transformations using InputFilter with FilterFlag.NoMarkup
FilterFlag.NoScripting
When this flag is set, the InputFilter method attempts to remove any malicious markup within the input, as defined by a set of blacklisted HTML tags (e.g. form, script, and object). An appropriate use for this flag would be in instances where some limited HTML input was permitted (for example, a forum post) but malicious script must nonetheless be defended against. Because this configuration utilizes a blacklist set of disallowed tags, as opposed to a stronger whitelist set of allowed tags, this flag should only be used over FilterFlag.NoMarkup when specific use-scenario warrants its use.
FilterFlag.NoSQL
In a manner similar to the FilterFlag.NoScripting flag above, setting this flag causes a blacklisted set of dangerous SQL tokens to be removed from an untrusted source. In this manner, a developer may protect against SQL injection attacks – especially when the input text is used in conjunction with ad-hoc or dynamic SQL execution. Note, however, that many modern development techniques (such as parameterized stored procedures) offer greatly increased protection over that which is afforded here. Whenever possible, these techniques should be relied upon, and the FilterFlag.NoSQL filter should be used a secondary line of defense.
FilterFlag.MultiLine and FilterFlag.RemoveAngleBrackets
These flags exist, respectively, for legacy and one-off scenarios, and as such should rarely (if ever) be used during development. The MultiLine flag was historically utilized to replace newlines with a HTML line-break tag (“<br />”); this flag is no longer used within the core framework and exists as a likely candidate for deprecation.
Similarly, the RemoveAngleBrackets flag simply removes angle brackets (“<” and “>”) from the input if and only if a RemoveAngleBrackets key is specified in the appSettings portion of the web.config. This flag does not provide any meaningful security (especially over the NoMarkup flag discussed above), and was included at the request of a major customer (1). As such, few if any circumstances exist that would warrant its use.
Combining Flags and Caveats
Because the flags associated with the InputFilter method exist as a bit field, multiple flags may be specified within a single call. An example of this is demonstrated in listing 1, where the input data will be encoded (via the FilterFlags.NoMarkup bit) and all blacklisted tags will be stripped (via the FilterFlags.NoScripting bit).
Dim untrustedText =_
“<h1>Markup</h1><script>alert(‘’);</script>”
Dim sanitizedText = New PortalSecurity()
.InputFilter(untrustedText, _
FilterFlag.NoMarkup Or Filterflag.NoScripting)
Debug.Assert(sanitizedText = “<h1>Markup</h1>”)
Listing 1: A sample InputFilter call specifying two flags
In general, the flags may be combined in any way that an end-developer desires, though in virtually all circumstances dealing with untrusted or user-supplied text the FilterFlag.NoMarkup bit will be set. However, there is one important exception to this rule that should be noted – whenever the NoSQL flag is specified, the NoMarkup, NoScripting, and Multiline flags are ignored. Since the NoSQL flag is designed to be used whenever a dynamic or ad-hoc SQL statement is about to be executed this is generally acceptable, but a developer should nonetheless be aware of this subtle behavior.
PortalSecurity.Encrypt, PortalSecurity.Decrypt, and PortalSecurity.CreateKey
These two methods, given a key and input, encrypt and decrypt the input and return it as a base64-encoded string. In this way, module developers may quickly obfuscate data that may be recovered elsewhere.
However, due to concerns about backward-compatibility, both of these methods internally utilize the DES algorithm. This algorithm is largely considered to be weak, and has been widely deprecated (3). Because of this, developers who require cryptographically-secure protection are advised to utilize other algorithms (such as AES or Triple-DES) until the DotNetNuke framework is enhanced to utilize a stronger encryption method; this is likely to occur in future release.
Finally, the PortalSecurity.CreateKey utilizes the RNGCryptoServiceProvider to generate a sequence of n pseudo-random bytes; these bytes are encoded as a hexadecimal string before being returned. This algorithm is considered to be secure, and may safely be utilized for cryptographic purposes (4). A code sample demonstrating the generation of a 128-bit key is illustrated in Listing 2.
Dim myKey As String = _
New PortalSecurity().CreateKey(128 / 8)
Listing 2: Sample code illustrating the generation of a 128-bit cryptographically-strong key
PortalSecurity.ForceSecureConnection
While DotNetNuke offers robust privacy options at the page level, allowing an administrator to require a private and confidential exchange (via SSL), there is currently no such option exposed at the module level. Thus, for modules which might present information that must not be viewed by third parties, it is up to the developer to ensure that privacy is maintained.
The PortalSecurity.ForceSecureConnection may be utilized for this purpose; when called, it will ensure that the HTTPS-protocol is in use for the current request, and, if not, will redirect to a URI that utilizes a HTTPS-connection. Developers should carefully consider the sensitivity of the data presented in a module in determining if data privacy should be a precondition of display.
PortalSecurity.SignOut and PortalSecurity.ClearRoles
The PortalSecurity.SignOut method may be utilized to de-authorize a user from the DotNetNuke application. In addition to making a call to FormsAuthentication.SignOut, this method explicitly clears all DotNetNuke-related cookies (e.g. current language, authentication type, and cached portal association).
Similarly, the PortalSecurity.ClearRoles method clears the security roles associated with a user that might be cached in that user’s cookies. This method is useful when a role is added or removed from the current user; a call to ClearRoles will ensure that the change is reflected immediately (rather than after cache expiration).
PortalSecurity.IsInRole and PortalSecurity.IsInRoles
As their names suggest, these methods are used to determine if the currently-authorized user is a member of a given role (or roles). When utilizing the plural version, a semicolon-separated list of roles is expected (e.g. “All Users;Subscribers”). Deny permissions may be included by including a “!” prefix on any role. For example, “!Subscribers” would return false for any user who was a member of the Subscribers role.
Listing 3 illustrates some uses of these methods.
If(PortalSecurity.IsInRole(“Administrators”)) Then
Response.Write(“You are an administrator.”)
Else If(PortalSecurity.IsInRoles(“Gold User;Subscribers”)) Then
Response.Write(“You are a gold user OR you are a subscriber.”)
End If
Listing 3: Sample code illustrating the use of the PortalSecurity.IsInRole and PortalSecurty.IsInRoles methods.
File System Services
DotNetNuke exposes a robust set of classes and static utility methods that may be used to interact securely with the file system. In many cases the appropriate leveraging of these services will save a developer considerable time and effort in effectuating a design, and at the same time serve to increase overall application-security. In this section we briefly examine the objects and utilities available to such a developer.
The low-level classes used to interact with the file system through DotNetNuke are located in the DotNetNuke.Services.FileSystem namespace. At this level, the most commonly used classes will be the two controllers FileController and FolderController along with their respective entities, FileInfo and FolderInfo. However, DotNetNuke also exposes a set of (generally static) utility methods that are sufficient to meet the needs of most developers. Whenever possible, utilize these methods, located in the DotNetNuke.Common.Utilities.FileSystemUtils class.
Whenever possible, utilize the methods located in the DotNetNuke.Common.Utilities.FileSystemUtils class for file system manipulation
In addition to files stored on the server’s file system, DotNetNuke offers two additional storage methods: the secure file system and database-secured files. Files persisted to the secured file system are persisted to the server file system as usual, except that the file has a “resources” extension appended to its name. Because files with this extension are not served by IIS, all such files are inaccessible by direct URI request, and may only be accessed via a special DotNetNuke HttpHandler (accessed via LinkClick.aspx) or through the DotNetNuke API. Database-persisted files are, as one would expect, stored directly inside the database, and like their secured file system counterparts, may only be accessed via API. Irrespective of storage strategy, the DotNetNuke API may be used to access all files within the application. To this end, all relevant methods require an instance of the enumeration FolderController.StorageLocationTypes to indicate which storage method is expected (unsecured, secured, or database-secured). Table 3 summarizes these storage types.
| Storage Location Type |
Description |
| InsecureFileSystem |
Files persisted under this storage type are written to the underlying file system as-is, and may be served directly by IIS (usually bypassing both DotNetNuke and ASP.NET). |
| SecureFileSystem |
Files persisted with this type are written to the underlying file system with a “resources” extension, ensuring that it will not be served by IIS (and thereby is not accessible by direct URI). |
| DatabaseSecure |
With this storage method, files are persisted directly in the DotNetNuke database. This is the arguably the most secure method of storage, but also the least efficient. |
Table 3: Members of the StorageLocationTypes enumeration, used to indicate where a file is stored in a DotNetNuke installation.
Exceptions, Logging, and Disclosure-Prevention
The Common Weakness Enumeration (CWE) classifies error information message leaks as being one of the most dangerous security-related programming errors (5), yet many developers remain unaware of the consequences associated therewith. To this end, DotNetNuke offers a number of logging and exception-handling methods designed to properly deal with errors and present minimal information useful to an attacker.
Developers will typically utilize the methods in the ExceptionLogController class and Exceptions module when preventing the disclosure of exceptions. The ExceptionLogController exposes a single method, AddLog, with several overloads for specific situations. Developers will typically utilize this method in situations where an exception needs to be logged but the module is otherwise able to handle the issue and proceed. Listing 4 illustrates one such example.
Try
Using myReader As New StreamReader("myFile.txt")
' Use the stream ...
End Using
Catch ex As FileNotFoundException
Dim controller = New ExceptionLogController()
controller.AddLog(ex)
' Recover and continue ...
End Try
Listing 4: Sample code illustrating the use of ExceptionLogController.AddLog, where a module needs to log the issue, but is otherwise able to recover and continue.
Some errors may be anticipated at design-time but aren’t otherwise handleable by a developer. In this case, the module should take advantage of the ProcessModuleLoadException method of the Exceptions module; this pattern is illustrated in listing 5. Note that uncaught exceptions, including those that are not anticipatable at design-time, will still be caught by the framework, where an appropriate error message will be displayed (with no risk of information leakage).
Try
DoSomethingThatMightCauseAnUnexpectedException()
Catch ex As MyUnexpectedException
ProcessModuleLoadException(myErrorMessage, Me, ex, True)
End Try
Listing 5: Sample code illustrating the use of Exceptions.ProcessModuleLoadException method.
Security Policy Services
DotNetNuke is designed to run in a wide range of environments, including both medium trust and custom security configurations. For developers that need to take advantage of functionality that may not be authorized in a particular environment, the DotNetNuke framework offers several methods to aid in determining this fact. The DotNetNuke.Framework.SecurityPolicy class is used to this end.
Table 4 summarizes the relevant methods available to developers.
| Method Name |
Description |
| HasAspNetHostingPermission() |
Indicates whether the application has been granted the AspNetHostingPermission permission |
| HasReflectionPermission() |
Indicates whether the application has been granted ReflectionPermission |
| HasWebPermission() |
Indicates whether the application has the WebPermission permission. |
Table 4: Policy-Relatedmethods of the DotNetNuke.Framework.SecurityPolicy class
Conclusion
The DotNetNuke framework is designed with security in mind, and offers framework-level solutions to meet the most common concerns of extension developers. Through the judicious use of the DotNetNuke authorization, privacy, input filtering, policy, and exception-management services, developers may focus on the implementation of business functionality rather than often-tedious security details. Because of this, DotNetNuke developers are able to design and deploy extensions that are more secure, more quickly, and with less overall development effort.
References
- Cullmann, Stefan. Upcoming Form and List Features: Private Columns and Filters. DotNetNuke. [Online] November 15, 2008. [Cited: September 22, 2009.] http://www.dotnetnuke.com/Community/Blogs/tabid/825/EntryId/2081/Upcoming-Form-and-List-Features-Private-Columns-and-Filters.aspx.
- Connolly, Cathal. DotNetNuke Module Security: Filtering User-Entered Text. The Mighty Blog. [Online] April 23, 2009. [Cited: September 25, 2009.] http://www.willstrohl.com/Blog/tabid/66/EntryId/377/DotNetNuke-Module-Security-Filtering-User-Entered-Text.aspx.
- Kelly, S. Security Implications of Using the Data Encryption Standard (DES). 2006. RFC 4772.
- Eastlake III, D., Schiller, J. and Crocker, S. Randomness Requirements for Security. 2005. RFC 4086.
- The MITRE Corporation. 2009 CWE/SANS Top 25 Most Dangerous Programming Errors. Common Weakness Enumeration. [Online] 1.3, July 27, 2009. [Cited: September 15, 2009.] http://cwe.mitre.org/top25/.