Daniel Ovaska
Dec 1, 2016
  16546
(11 votes)

Security checklist for Optimizely or .NET website

So you have built a great website for your customer, but is it secure? Code review your solution for these top issues. 

Added some levels to indicate in what order I would do them in. 

  • Level A - Most important fixes / low effort that all sites should have yesterday.
  • Level AA - Important / medium effort
  • Level AAA - If you complete these you are probably top 1% of the sites out there in terms of security.

Level A

  • Use Https

    Without https you are wide open for a whole bunch of man-in-the-middle (MITM) attacks. Don't release a site without it. Use it on the entire site and not only on the logged in part. Check that you are using at least TLS 1.2 and disallow older versions 
    https://docs.microsoft.com/en-us/configmgr/core/plan-design/security/enable-tls-1-2
    You can also add the following to global.asax for older .NET versions (4.5) for application start to force all outgoing requests to use TLS 1.2

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
  • Secure edit and admin mode

    For the strongest security, use a separate editor server node. If the public server doesn't even have publishing capabilities, that part is much more secure. Check option 2 on the url below:
    http://world.episerver.com/blogs/Chris-Bennett/Dates/2009/12/Server-Architecture-Options-for-EPiServer/

    Shut down edit mode on public web front

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <configuration>
      ...
      <location path="episerver">
        <system.web>
          <authorization>
            <deny users="*" />
          </authorization>
        </system.web>
      </location>

    If you can't afford it, at least choose hard-to-guess custom urls for util and cms and force your editors to use strong passwords.

    Another cheaper option instead of a separate editor server is to use ip restrictions for the relevant directories to lock the server down.

    1
    2
    3
    4
    5
    6
    7
    <system.webServer>
        <security>
            <ipSecurity allowUnlisted="false" denyAction="NotFound">
                <add allowed="true" ipAddress="123.456.0.0" subnetMast="255.255.0.0"/>
            </ipSecurity>
        </security>
    </system.webServer>

    The default ip blocking will not work in DXP however, check this blog post for that

    • Secure cookies

      For an https site, your session cookies and authentication cookies should be marked as secure. Small fix to web.config required. Might need to have a few lines of code in the end request event in global.asax to handle the authentication cookie as well. See http://stackoverflow.com/questions/3428556/authcookie-not-secure-in-global-asax

      <configuration>
          <system.web>
            <httpCookies requireSSL="true" />
    • Turn off detailed errors and set compilation mode to release

      Easily done in web.config. https://www.owasp.org/index.php/ASP.NET_Misconfigurations

    • Avoid click jacking attacks

      Add a response header for X-Frame-Options.

      <system.webServer>
          <httpProtocol>
            <customHeaders>
              <add name="X-Frame-Options" value="SAMEORIGIN" />
            </customHeaders>
          </httpProtocol>
    • Restrict editors

      Give them the least access rights needed and avoid making shared accounts. If something goes wrong, you want to know who did what. Use WebEditors to give access to edit mode only and a separate role to give access to the part of the content tree "Editors_Sweden, Editors_Norway" or similar. 

    • Remove test users

      Especially all admin accounts to EPiServer and similar that was used during development needs to be deleted before launch.

    • Use a service account for scheduled jobs and similar

      It happens that the developer uses his own account instead of creating a separate service account to run scheduled jobs. Don't.

    • Check that your search result page (SRP) never displays secured content.

      Depending on search solution, this can be a problem. I've seen it a couple of times that excerps are shown on the SRP of secured content to the anonymous user. Double check that pages in waste basket isn't shown.

    • Check that pages in waste basket is not shown / crashes site

      If you list content in any way by using GetChildren / FindPagesByCriteria in the background, make sure you filter your list for access rights before displaying them. EPiServer controls do this out-of-the-box but if you use custom code to render your lists/menus you will have to solve this problem to avoid any issue. Test by sending some content to wastebasket and check that they are handled correctly. They should not be visible in menus or in search results for instance.

    • Move your log files

      Having your log files in web root is not a good idea from a security point of view. EPiServer has log4net as logging tool and by default they end up in webroot if you turn on logging. They should ideally be on a separate harddrive (since it happens that too large log files crash the website).

    • IIS File access rights

      Double check that your file access rights are correct and that noone added full access rights for everyone when they were troubleshooting something. Check this url if you are unsure:

      http://www.iis.net/learn/get-started/planning-for-security/understanding-built-in-user-and-group-accounts-in-iis

    • Email is not a secure channel

      Never send passwords and similar on email. Send a temporary link instead.

    • Remove unused membership providers (CMS 11 and earlier)

      If you don't use your windows membership provider, remove it.

    • Turn off detailed error messages for WCF
      1
      2
      3
      4
      5
      6
      7
      8
      <configuration>
         
          <system.serviceModel>
              ...
              <behaviors>
                  <serviceBehaviors>
                      ...
                      <serviceDebug includeExceptionDetailInFaults="false" />
    • Check vulnerabilities in used frameworks node modules / nuget
      Easy to do with npm audit if you are using node modules. Running an audit using chrome will also show javascript vulnerabilities. 
      Locking external packages to a specific version to avoid automatic upgrades by build servers is a good idea. Using signed packages if possible is another, especially for secondary feeds like a private feed. Beware of private package high jacking detailed below if you are using multiple package sources. Visual studio 2022 has an excellent function in nuget package manager where it can display vulnerable packages in solution.
      Include this in your development process regularly, read more
      https://world.optimizely.com/blogs/Daniel-Ovaska/Dates/2024/6/keeping-the-website-secure-by-updating-external-packages/

    • Avoid leaking user data to countries you do not trust with frontend scripts (GDPR)
      Some scripts like google analytics and hotjar provide great functionality but is also a security risk that needs to be discussed. How much user data from your site are you willing to let someone else in another country control? You can easily see to which country you are sending user data to using running this script in your google chrome console window
      https://github.com/tomper00/privacy-test-your-site/blob/main/scan-site.js

    • Require strong passwords

      Long passwords beat complex passwords. A minimum of 9 characters is recommended. Preferably more if your users don't start screaming too loud. This is easy to configure on your membership provider in web.config. Make it possible to copy passwords to enable password managers to work well.

    Level AA

    • Use 2 factor authentication (2FA) for login

      This will help secure your site against brute force attacks guessing passwords and also make it less sensitive if an email account is hacked. Many federated login services has support for 2FA.

    • Check SSL certificate

      Old versions of protocols and algorithms are vulnerable to attacks. Use for instance:
      https://www.ssllabs.com/ssltest/analyze.html or
      https://cryptoreport.websecurity.symantec.com/checker/views/certCheck.jsp
      to check if you are using the latest and greatest without known security holes.

    • Prevent cross site forgery

      Do use the [ValidateAntiForgeryToken] attribute in MVC controller for post actions and @Html.AntiForgeryToken() in your views. Check out some nasty example on http://blog.stevensanderson.com/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/

    • Have a company security feedback process
      If Troy Hunt says jump the proper response is "How high?". Seriously though. You need to have a feedback function on your website where people can report security issues in a safe way. The proper response to someone reporting a security issue is "Thank you. We will look into it." 
      If you fail on this it might mean that someone decides to report the issue to the local paper instead to warn of an unsafe site. You don't want that

    • Double check your content caching strategies

      Make sure you never cache non-public content. E.g. if you cache the menu (that is filtered on access rights) and you then surf around with an admin user followed by an anonymous user you might show menu items that only admins should see to the anonymous user. Normally you don't need to cache EPiServer content lists if you just use GetChildren. EPiServer does that for you.

    • Secure your data layer

      Make sure you use an ORM like EF that doesn't allow SQL injections and that you never ever string concat an SQL statement together. If you run SQL stored procedures it might be worth checking those for string concatenation as well. I've seen some ugly code hidden there as well...

    • Secure your service layer

      For websites that are more application oriented, it's wise to secure your service layer so that some functions are only available to certain roles e.g. delete user can only be run by someone logged in as administrator. It's easy to solve this by simply hiding the button for this in the presentation layer but a more secure way is to add it above your service layer. I use custom attributes and AOP for this but the exact implementation is less important.

    • Lock down webservices and handlers

      It's easy to get lazy when EPiServer is handling security for content out-of-the-box. Check through your solution for other access points that the solution uses like webservices, web api, handlers etc and secure them / validate all input.

    • Lock down plugins and other .NET files

      Check if you have admin/editor plugins, regular aspx files and similar and secure them. This can normally be done easily by adding a location tag in web.config and restrict it to a certain role

    • Validate querystring parameters and api input

      Similar to the one above but easier to forget but equally important. Let's avoid those pesky sql injections and similar.
      If a user sends a customerId, does that user actually have access to that customerId?

    • Server side request forgery (SSRF)
      With SSRF, the attacker can trick the backend itself to do requests to harmful urls. Example: Imagine you have a report generator that lists names of users in system, creates an html file and then generates a report based on that html. Now one user changes their name to <img src="http://badsite.com" />. That means that when server lists users and renders that html in backend it will try to get that image and send a request to that server. The user has tricked that backend to issue a request to a url it really shouldn't. 
      Clean all input from users and avoid letting users use html if possible.
      Whitelist allowed characters. If possible also have a whitelist in firewall of allowed outgoing domains and ips. 
    • Html encode all output (XSS)

      Especially important for all data that comes from other systems / user input to avoid javascript cross site scripting (XSS) attacks.

      For webforms, check that you are using webcontrols that support htmlencoding or the

      <span class="label label-info"><%#: Item.QuestionNumber %></span>

      If you are using MVC, use the standard Model. syntax and stay away from Html.Raw as much as possible.

    • Reverse tab nabbing

      For external links that open in a new window, also set the rel attribute to noopener to protect against reverse tab nabbing attack 
      <a href="some-external-link" rel="noopener" target="_blank">Some External Website</a>
    • Use my performance checklist to protect vs DDoS attacks
      Link to performance checklist

    Level AAA

    • Enable HSTS
      This is used to secure https one step furter to disallow any http requests whatsoever. If you only use a http => https redirect it leaves a security hole where a man-in-the-middle can hijack the request. 
      https://www.troyhunt.com/understanding-http-strict-transport/
      https://hstspreload.org/
    • Protect vs XXE (Xml Extended Elements)
      Read more here. Part of OWASP top 10 list. 
      Avoid using XmlTextReader at all and make sure you have .NET version 4.6 or higher and you should be pretty safe.
      If you have to use XmlTextReader use
      XmlTextReader myReader = new XmlTextReader(new StringReader(xml));
      myReader.DtdProcessing = DtdProcessing.Prohibit;​
    • Use Content Security Policy, CSP to protect against XSS attacks
      https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP

    • Use a single package source for nuget / node packages
      If you don't you will likely be vulnerable to supply chain attacks. If you decide to use multiple sources like an additional private package source you will need to add extra security measures. This is because it's possible to create a new version of your private package on the public package source which will then be downloaded instead. Having a single package source protects against this. Signed packages and locking down versions to a specific version to avoid automatic upgrades on CI server also helps reducing risk.
      https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-24105  
    • Use external PEN test to test security on your site
      A bit expensive but worth it for sites that need higher security
    • Use a code scanner like Azure Advanced security in build pipeline
      Good to set up as separate pipeline since it's slow. For huge projects you might need dedicated azure build agents with more than usual disk space I've noticied. This should be rare though. License cost is per active developer in team.

    If you went through this checklist you will hopefully have a more secure site than you had before. Do check out the OWASP top 10 for official recommendations as well. Nothing is unbreakable of course but let's avoid the obvious security holes at least. Ending up in the news because your website got hacked is not fun. 

    Dec 01, 2016

    Comments

    Jun 17, 2015 04:39 PM

    Great list Daniel!  This covers many of the OWASP points. 

    I'd add to this to remember to secure any plugin URLs you add for custom plugins.  If you have a folder called Plugins for example simply add another Location node in your web.config to secure ~/Plugins

    Jun 17, 2015 06:56 PM

    Where did the "Test this websites security" button go? ;-)

    Jun 17, 2015 07:21 PM

    They got the message Oerjan :)

    Lets leave it at that, sorry for my poor sense of developer humor.

    Jun 18, 2015 08:53 AM

    I added your suggestion to the list Janaka. I've seen some admin plugins that wasn't secured correctly so it's definitely something to think about.

    Arve Systad
    Arve Systad Jun 22, 2015 09:56 AM

    Neat list, but regarding validating user input: I'd rather do things properly and protect myself against SQL attacks in other ways than not letting "Dr. Ing. John-Peter Mc'Doe" register with his proper name. And for email-adresses, you can be pretty sure to miss out on something that's actually allowed by using one of the thousands of "email regexes" out there. I know 99% of people will do just fine with just [a-Z] in the name, but for those pesky exceptions, it's going to be a nightmare to use your site.

    Protect against SQL injections by using properly protected existing APIs, or parameterized SQL if you're doing that part yourself.

    Jun 22, 2015 08:05 PM

    So to sum up Arve:

    Yes to using existing API and parameterized SQL

    No to storing any user input as name or email or any text field without server validation vs white list of characters. Too risky for XSS if nothing else.

    Henrik Fransas
    Henrik Fransas Jun 23, 2015 09:11 AM

    I will also add the possibility to secure the editing part with ip-restrictions so you are only alowing users that are logged in to your own network to access it.

    https://www.stokia.com/support/misc/web-config-ip-address-restriction.aspx

    Nice list, thanks a lot!

    Jun 23, 2015 09:18 AM

    That's a decent cheap solution instead of having a separate server for editors. Definitely a useful option that I'll add to the list, thanks for the input!

    Jun 23, 2015 11:29 AM

    Yes, message received.

    I've blocked script inclusions in blog posts, at least the most obvious way of doing it. If you used some other trick please don't blog about it - drop us a line at epw@episerver.com. :)

    May 10, 2016 10:23 AM

    Updated post with a few more items and some examples...

    Jun 15, 2016 01:12 PM

    Updated post after my latest PEN test and OWASP test of a new website with some SSL suggestions...PEN test went great btw :)

    Dec 1, 2016 03:06 PM

    Updated with some more tools from mr Jones

    Dec 1, 2016 04:04 PM

    Hmm, wonder why it was dated to 1st of december 2016 again just because I updated it. Oh well...nm :)

    Arve Systad
    Arve Systad Dec 1, 2016 07:58 PM

    I'd just say "Use HTTPS" regardless of anything. It's cheap and ensures the integrity of your site, even if you have no log-in-functionality. Ever used In flight-WIFI that puts ads on your site? This is in practice a man-in-the-middle-attack, which is not possible if running on HTTPS.

    valdis
    valdis Dec 8, 2016 09:41 PM

    Chrome will get you warnings in your face when site is not running on HTTPS. I would say - that's not recommendation, but demand instead.

    Aug 30, 2017 09:40 AM

    Here two pages that can test your site security.

    https://www.ssllabs.com/ssltest

    https://securityheaders.io

    However, verify the implementation on a dev/test/stage environment first, before it is placed at a production environment.

    Daniel Ovaska
    Daniel Ovaska Feb 25, 2021 09:57 AM

    Updating with information about high jacking private package sources if you are using multiple sources for nuget / node etc.

    Please login to comment.
    Latest blogs
    SaaS CMS and Visual Builder - Opticon 2024 Workshop Experience

    Optimizely is getting SaaSy with us…. This year Optimizely’s conference Opticon 2024 took place in San Antonio, Texas. There were a lot of great...

    Raj Gada | Dec 30, 2024

    Copy Optimizely SaaS CMS Settings to ENV Format Via Bookmarklet

    Do you work with multiple Optimizely SaaS CMS instances? Use a bookmarklet to automatically copy them to your clipboard, ready to paste into your e...

    Daniel Isaacs | Dec 22, 2024 | Syndicated blog

    Increase timeout for long running SQL queries using SQL addon

    Learn how to increase the timeout for long running SQL queries using the SQL addon.

    Tomas Hensrud Gulla | Dec 20, 2024 | Syndicated blog

    Overriding the help text for the Name property in Optimizely CMS

    I recently received a question about how to override the Help text for the built-in Name property in Optimizely CMS, so I decided to document my...

    Tomas Hensrud Gulla | Dec 20, 2024 | Syndicated blog