Drupal's default settings provide rather loose security. In this second article in a series, I review Drupal configuration changes to tighten security and control who can create and view content.
Table of Contents
- Lock down Drupal accounts
- Disable Drupal's anonymous user account creation
- Block logins to generic Drupal accounts
- Create Drupal user roles
- Assign users their user roles
- Set Drupal user role permissions
- Set up SSL for Drupal logins
- Restrict the content users can create
- Create a safe filtered input format for Drupal's anonymous users
- Create a safe filtered input format for Drupal's trusted users
- Restrict access to Drupal's unfiltered input formats
- Install a spam filter module in Drupal
- Restrict access to PHP code fields
- Prevent PHP access by disabling Drupal's "administer filters" permissions
- Prevent PHP access by disabling Drupal's "administer blocks" permissions
- Prevent PHP access by disabling Drupal's "administer views" permissions
- Prevent PHP access by disabling Drupal's "administer content types" permissions
- Restrict the nodes you list
- Restrict views to only show published nodes
- Restrict views to only show non-administrative nodes
- Restrict access to administrator views
- Block listing administrative vocabularies in the public site map
- Block listing administrative vocabularies in taxonomy views
- Restrict the nodes you index and show in a search
- Restrict the content users can view
- Don't depend upon unpublished Drupal content being inaccessible
- Restrict access to specific Drupal nodes and content types
- Restrict access to specific Drupal menus
- Restrict access to specific Drupal blocks
- Further reading
This is part 2 in a series of web site security checklists. Part 1 reviewed Apache and Drupal settings to restrict access to files and directories, and Part 3 reviews Apache and Drupal settings that leak status and configuration information about your site to would-be hackers.
The Web Application Security Consortium (WASC) maintains a Web Hacking Incident Database (WHID) that records major hacking incidents and how they occurred. In a 2008 report (PDF), Breach Security summarized this data into a top ten list of the apparent hacker goals:
Top Ten Hacker Goals Goal % Defacement 24% Stealing sensitive information 19% Planting malware 16% Monetary loss 13% Downtime 8% Phishing 5% Deceit 2% Worm 1% Link spam 1% Information warfare 1%
Web masters sometimes argue that security isn't that important because they've got nothing worth stealing. But note that the top attack goal is simply to deface the site. If we add together percentages for defacement, planting malware, phishing, deceit, and link spam, then 48% of hacker goals just involve posting bad content to your site. This can put your users at risk with malware and damage your site's reputation. Tightening security is important, even if you think you have nothing worth stealing.
Web masters for small sites might also argue that they are too small to be noticed. Automated attack tools, however, don't care if your site is big or small. They simply scan through IP addresses looking for vulnerabilities they can use. The Internet Storm Center collects statistics on the length of time between automated attacks for an average target IP address. The answer: 6 minutes.
Your web site will be attacked. It's only a matter of time. This article looks at Drupal configuration changes that limit who can post content to your site and who can view it.
Let me repeat from the first article:
- I do not discuss downloading or installing software or setting up directories, permissions, and chroot. How you do these is important, but beyond the scope of this article.
- I do not discuss basic Apache, PHP, MySQL, and Drupal configuration. I assume that you've already got things working and now you're ready to tighten security.
- This list is not exhaustive. No list could be.
- All of these settings have been tested, but test them yourself before using them on a production site. Every site is different.
Lock down Drupal accounts
Control how users create Drupal accounts, and what they can do with them.
• WASC classifies account problems as Insufficient Authentication weaknesses. In a 2009 report (PDF), White Hat Security's top ten security issues includes this threat as number nine with a 10% likelihood amongst web sites they tested.
Disable Drupal's anonymous user account creation
By default, Drupal enables anonymous users to create a new account without asking you first. If you're creating a public forum-style site, that may be fine. But if you're creating a blog or a site for a small business, you need tighter control. Disable un-approved account creation on Drupal's Administer > User management > User settings page.
Block logins to generic Drupal accounts
Create Drupal user roles
Drupal user roles give a name to a group of permissions for viewing and creating content and administering the site. By default, there are only "anonymous user" and "authenticated user" roles. This doesn't provide much granularity for controlling access. Consider adding an "author" role for users that can create and edit content, a "moderator" role for users that can approve comments and delete offending content, and an "administrator" role for users that can make limited changes to the site's configuration. Create roles on Drupal's Administer > User management > Roles page.
Assign users their user roles
With user roles created, go to each of the user accounts and set their roles. User accounts are listed on Drupal's Administer > User management > Users page.
Set Drupal user role permissions
Whether or not you create additional user roles, be sure to set role permissions. Go to Drupal's Administer > User management > Access control page and start by unchecking everything. Now, go back through the permissions and grant anonymous users the ability to view some or all of your content, but never to edit it or administer your site. If you plan on letting lots of people have accounts, restrict authenticated users to the bare minimum. For all settings, err on the side of paranoia. Don't grant a permission unless you are sure that the user role needs it.
Set up SSL for Drupal logins
Drupal does not support SSL encrypted logins directly, but there are multiple articles discussing ways to set it up. Since this can vary a lot from site to site, I cannot discuss it directly. Many solutions involve the Secure Pages module.
Restrict the content users can create
Drupal content can include HTML text, forms, styles, scripts, and even executable PHP code. For web masters, this is very flexible. It can also be very dangerous.
- PHP code in content is executed on the server where it has access to everything. Malicious code could destroy the site. So, block all users except the web master from creating content with embedded PHP code.
- HTML could include scripts executed in the users' browser where they have access to site cookies. Malicious code could send private cookie data elsewhere and make a mess of the site. Block all users except the web master from creating content with embedded scripts.
- HTML could include styles, iframes, forms, and images that present foreign content as part of your site, or that simply make a mess of your styling. Block all but the most trusted users from creating content with these HTML tags.
Use Drupal's input formats to filter all content before it is displayed on a web page.
Create a safe filtered input format for Drupal's anonymous users
Drupal's default "Filtered HTML" input format restricts content to basic paragraph, list, and formatting tags. Adjust this to suite your site but avoid abusable tags like <script> <style> <iframe> <form> and <object>. Be sure the "PHP code" option is not checked so that users cannot include PHP code. Make this input format the default choice and configure it on Drupal's Administer > Site configuration > Input formats page. For example, allow:
<a> <b> <bdo> <blockquote> <br> <code> <dd> <dl> <dt> <em> <i> <li> <ol>
<p> <pre> <span> <strong> <sub> <sup> <tt> <ul>
Create a safe filtered input format for Drupal's trusted users
Drupal's default "Full HTML" input format allows anything, including <script> <iframe> <form> and <object>. That's too much, even for trusted users. Instead, create a new input format for trusted users that allows most HTML, but not scripts, objects, and forms. Input formats are created on Drupal's Administer > Site configuration > Input formats page. For example, allow:
<a> <abbr> <acronym> <address> <area> <b> <base> <bdo> <big> <blockquote> <br>
<caption> <cite> <code> <col> <colgroup> <dd> <dfn> <div> <dl> <dt> <em>
<h1> <h2> <h3> <h4> <h5> <h6> <hr> <i> <img> <legend> <li> <map> <ol>
<p> <pre> <q> <samp> <small> <span> <strong> <style> <sub> <sup>
<table> <td> <tfoot> <th> <thead> <tr> <tt> <ul> <var>
Restrict access to Drupal's unfiltered input formats
After you've set up filtered input formats for anonymous and trusted users, block access to all unfiltered input formats. Keep the "Full HTML" format but make it available to the web master only. Also block Drupal's default "PHP code" format that allows executable PHP code. Set filter permissions on Drupal's Administer > Site configuration > Input formats page.
Install a spam filter module in Drupal
Spam filters use heuristics to decide if content is or is not spam. Content that looks spam-y is redirected to an approval queue where a moderator must decide what to do. Consider the Akismet, Mollom, and Spam modules. Each one has configuration pages in Administer > Site configuration.
Restrict access to PHP code fields
There are several places in Drupal where authors can insert PHP code. Restrict these pages to the web master only.
• WASC classifies code creation problems as Insufficient Authorization and Application Misconfiguration weaknesses. Of course, once bad PHP code has been inserted, that code can create all sorts of additional problems.
Prevent PHP access by disabling Drupal's "administer filters" permissions
It does no good to set up safe filtered input formats if users can change them. Disable everyone's "administer filters" permission on Drupal's Administer > User management > Access control page. Once disabled, users cannot enable "PHP code" execution to the filters they use.
Prevent PHP access by disabling Drupal's "administer blocks" permissions
Page blocks can be shown or hidden based upon a bit of PHP code. Block user access to this feature by disabling the "administer blocks" permission on Drupal's Administer > User management > Access control page.
Prevent PHP access by disabling Drupal's "administer views" permissions
Views can have arguments that are set by a bit of PHP code. Block user access by disabling the "administer views" permission on Drupal's Administer > User management > Access control page.
Prevent PHP access by disabling Drupal's "administer content types" permissions
CCK content types can have default values set by PHP code fragments. Block user access to this by disabling the "administer content types" permission on Drupal's Administer > User management > Access control page.
Restrict the nodes you list
Most Drupal sites have internal content that shouldn't be listed or viewed. Some internal content is private, such as a web master's to-do list or security notes on problem users. Some internal content isn't ready for publication yet, such as nodes or comments waiting in a moderator queue. And some internal content is an artifact of site structure, such as the site's "Page not found" and "Access denied" error pages.
Restrict views to only show published nodes
Drupal's Views module creates lists of nodes meeting your filter criteria. The first filter in every Drupal public view should be to only list published nodes. Edit views on the Administer > Site building > Views page.
Restrict views to only show non-administrative nodes
If your site includes internal nodes for administrative content, it helps to use a custom CCK content type for those pages. Then check all of your views to include a filter to exclude content of that type from public lists of nodes. Edit views on the Administer > Site building > Views page. Be sure to override Drupal's default views, such as "frontpage", "popular_alltime", "popular_recent", and "tracker".
Restrict access to administrator views
Web masters may use their own administrator views to list unpublished content, security notes, and more. Restrict access by setting the user roles that may access a view on each view listed on the Administer > Site building > Views page. Be sure to disable the "access all views" permission for all user roles on the Administer > User management > Access controls page too, or view-specific user roles will be ignored.
Block listing administrative vocabularies in the public site map
Drupal's Site Map module is a handy way to automatically maintain a public site map. By default, it lists all vocabularies and terms. However, some vocabularies may be an artifact of site structure and others may be for administrative use only. These vocabularies and terms should not be listed publically, so configure the module to skip them using the Administer > Site configuration > Site map page.
Check your public site map by going to "http://YOURSITE/sitemap".
Block listing administrative vocabularies in taxonomy views
Drupal's default "taxonomy_term" and "taxonomy_directory" views can list any vocabulary and its terms. If you have vocabularies for administrative use only, disable or override these views with your own and add view filters to exclude administrative vocabularies. Views are configured on the Administer > Site building > Views page.
Restrict the nodes you index and show in a search
Search is an essential feature for most web sites. Configure it to only index and display appropriate content.
Block listing administrative nodes in the XML site map
Drupal's XML Site Map module creates an XML site map that lists all site content for easier access by search engines. By default, it lists every published node at your site. However, some nodes are artifacts of site structure or contain administrative content. Search engines don't need to look at these.
If you use a custom content type for administrative nodes, you can exclude them all from the XML site map by setting its site map priority to "Not in site map" on the content type listed on the Administer > Content management > Content types page.
You can block any node from inclusion in the XML site map by editing the node and changing its site map priority to "Not in site map".
Check your XML site map by going to "http://YOURSITE/sitemap.xml".
Restrict access via Drupal search
Drupal's built-in search features index everything — every published node for every content type. While administrative nodes will not be shown to users unless their user roles allow access, some nodes must be public, and yet shouldn't be listed. For instance, your site's "Access denied" and "Page not found" nodes have to be publically accessible, but they should never show up in a search results list.
To restrict search access to some content, create a custom content type for these pages. Then install the Search Config module and configure it on the Administer > Site configuration > Search settings page. Disable indexing and display of administrative content types.
The Restricted Search module offers similar abilities to restrict search results by content type. It also adds a checkbox to every node to enable that specific node to be excluded from the search index. Configure the module on the Administer > Site configuration > Search settings page on the Restrict Search tab.
Restrict the content users can view
Some site content is intended strictly for the web master, or for managers, authors, moderators, etc. Drupal's user roles restrict specific actions, but not specific content. For that you need to adjust settings and add modules.
Don't depend upon unpublished Drupal content being inaccessible
Unpublished nodes and comments are still accessible. If you know the URL, or can guess it, unpublished nodes can be served. Since all Drupal nodes have a URL of the form "http://YOURSITE/node/NUMBER", it isn't hard for a hacker to write a script that cycles through consecutive NUMBER values to get every node at your site, published or not. You'll have to install additional modules to limit access on a node-by-node basis.
Restrict access to specific Drupal nodes and content types
Restrict access to specific Drupal menus
Drupal does not have per-menu or per-menu item viewing restrictions. Individual menu blocks can be restricted using user role restrictions on the Administer > Site building > Blocks page. To get more control, there are additional modules available, such as Menu Access.
Restrict access to specific Drupal blocks
Hide private blocks by setting block permissions on each block on the Administer > Site building > Blocks page.