<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><language>en</language><title>Blog posts by Petra Liljecrantz</title> <link>https://world.optimizely.com/blogs/Petra-Liljecrantz/</link><description></description><ttl>60</ttl><generator>Optimizely World</generator><item> <title>Common security issues with a CMS application</title>            <link>https://world.optimizely.com/blogs/Petra-Liljecrantz/Dates/2016/4/common-security-issues-with-a-cms-application/</link>            <description>&lt;p&gt;This is the fourth and final post about issues I encounterd working for Episerver Managed Services. We (and the entire support organization) often saw&amp;nbsp;some security issues in applications and I wanted to&amp;nbsp;share the four most common ones.&lt;/p&gt;
&lt;h2&gt;Exposed web services with debug tracing on&lt;/h2&gt;
&lt;p&gt;The attribute &lt;em&gt;includeExceptionDetailInFaults&lt;/em&gt;&amp;nbsp;is set default to &lt;em&gt;true&lt;/em&gt; and a default value is often transferred to a production environment as well, it should be set to false so exceptions are not included in the packages when, for example, a cache invalidation broadcast occurs in Episerver CMS.&lt;/p&gt;
&lt;p&gt;Set it like this:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;lt;configuration&amp;gt;
    &amp;hellip;
    &amp;lt;system.serviceModel&amp;gt;
        ... 
        &amp;lt;behaviors&amp;gt;
            &amp;lt;serviceBehaviors&amp;gt;
                ...
                &amp;lt;serviceDebug includeExceptionDetailInFaults=&quot;false&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Username and passwords are sent in plain text&lt;/h2&gt;
&lt;p&gt;This is one of those things that most developers actually know is bad but somehow it gets down prioritized&amp;nbsp;or just forgotten, so I can&amp;acute;t stress this enough.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Username and password are sent as plain text over the internet when logging in to edit mode, this makes it easier to listen to and get access to the servers. Use an SSL certificate to protect at least the login if not the entire site, the most common way is to terminate the SSL certificate in the server or load balancer with a wildcard certificate that can handle sub domains.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;&lt;span&gt;Unused role- and membership providers are exposed&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;An application should only use the &lt;em&gt;SqlServerRoleProvider&lt;/em&gt;&amp;nbsp;as the means of logging in (or ADFS) but usually both &lt;em&gt;MultiplexingRoleProvider&lt;/em&gt;&amp;nbsp;and&amp;nbsp;&lt;em&gt;WindowsRoleProvider&lt;/em&gt; are still loaded as role providers, the same goes for the membership providers. To minimize the attack surface it&amp;rsquo;s recommended to only expose active providers.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;WindowsMembershipProvider&lt;/em&gt; will expose the administrator account directly out on the internet available for brute force attacks. Therefore it&amp;acute;s recommended to simply remove the role- and membership providers not used from web.config.&lt;/p&gt;
&lt;p&gt;Here is an example of web.config transformations you can use to force this behavior:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;lt;!-- Set &quot;SqlServerMembershipProvider&quot; as default and remove the other providers --&amp;gt;
&amp;lt;membership defaultProvider=&quot;SqlServerMembershipProvider&quot; xdt:Transform=&quot;SetAttributes(defaultProvider)&quot; &amp;gt;
    &amp;lt;providers&amp;gt;
        &amp;lt;clear /&amp;gt;
        &amp;lt;add name=&quot;MultiplexingMembershipProvider&quot; xdt:Transform=&quot;Remove&quot; xdt:Locator=&quot;Match(name)&quot; type=&quot;EPiServer.Security.MultiplexingMembershipProvider, EPiServer.Framework&quot; /&amp;gt;
        &amp;lt;add name=&quot;WindowsMembershipProvider&quot; xdt:Transform=&quot;Remove&quot; xdt:Locator=&quot;Match(name)&quot; type=&quot;EPiServer.Security.WindowsMembershipProvider, EPiServer&quot; /&amp;gt;
    &amp;lt;/providers&amp;gt;
&amp;lt;/membership&amp;gt;

&amp;lt;!-- Set &quot;SqlServerRoleProvider&quot; as default and remove the other providers --&amp;gt;
&amp;lt;roleManager defaultProvider=&quot;SqlServerRoleProvider&quot; xdt:Transform=&quot;SetAttributes(defaultProvider)&quot; &amp;gt;
    &amp;lt;providers&amp;gt;
        &amp;lt;clear /&amp;gt;
        &amp;lt;add name=&quot;MultiplexingRoleProvider&quot; xdt:Transform=&quot;Remove&quot; xdt:Locator=&quot;Match(name)&quot; type=&quot;EPiServer.Security.MultiplexingRoleProvider, EPiServer.Framework&quot;  /&amp;gt;
        &amp;lt;add name=&quot;WindowsRoleProvider&quot; xdt:Transform=&quot;Remove&quot; xdt:Locator=&quot;Match(name)&quot; type=&quot;EPiServer.Security.WindowsRoleProvider, EPiServer&quot; /&amp;gt;
    &amp;lt;/providers&amp;gt;
&amp;lt;/roleManager&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Open edit mode on webfronts&lt;/h2&gt;
&lt;p&gt;All public servers expose EPiServer&amp;rsquo;s largest attack surface: the editorial and administrator interface, this is a security risk and in an environment that has one separate server for administrators to do their work and another (or several) servers acting as web fronts it&amp;acute;s a good recommendation to deny access to edit mode for all users (including editors and administrators as they should use the other server and that server should be protected by IP restriction or domain restriction).&lt;/p&gt;
&lt;p&gt;This is done by replacing the location path configuration in web.config to deny all users access to the paths&amp;nbsp;&lt;em&gt;&amp;ldquo;episerver/&amp;rdquo;&lt;/em&gt;,&lt;em&gt; &amp;ldquo;episerver/CMS/admin/&amp;rdquo; &lt;/em&gt;and&lt;em&gt; &amp;ldquo;/util&amp;rdquo;&lt;/em&gt;. Since the methods &lt;em&gt;HasEditAccess&lt;/em&gt; and &lt;em&gt;HasAdminAccess&lt;/em&gt; in &lt;em&gt;PrincipalInfo&lt;/em&gt; is based on this path you need to explicitly deny acces and not just remove the location path.&lt;/p&gt;
&lt;p&gt;Example of deny access to all:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;lt;configuration&amp;gt; 
  ...
  &amp;lt;location path=&quot;episerver&quot;&amp;gt;
    &amp;lt;system.web&amp;gt;
      &amp;lt;authorization&amp;gt;
        &amp;lt;deny users=&quot;*&quot; /&amp;gt;
      &amp;lt;/authorization&amp;gt;
    &amp;lt;/system.web&amp;gt;
  &amp;lt;/location&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span&gt;If&amp;nbsp;there&amp;acute;s no&amp;nbsp;separate admin server then you&amp;acute;ll want to restrict the edit and admin location path to only allow certain IP numbers. Episerver Managed Services&amp;nbsp;provide IP restrictions in the firewall, but a better way (in my opintion) to do it is in the application, through a setting in web.config. Then the customer or you as the developer can control that yourselves.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;This is all you need:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;lt;system.webServer&amp;gt;
    &amp;lt;security&amp;gt;
        &amp;lt;ipSecurity allowUnlisted=&quot;false&quot; denyAction=&quot;NotFound&quot;&amp;gt;
            &amp;lt;add allowed=&quot;true&quot; ipAddress=&quot;123.456.0.0&quot; subnetMast=&quot;255.255.0.0&quot;/&amp;gt;
        &amp;lt;/ipSecurity&amp;gt;
    &amp;lt;/security&amp;gt;
&amp;lt;/system.webServer&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The example configuration snippet shows an &lt;em&gt;ipSecurity&lt;/em&gt; configuration that only allows access to addresses originating from the range specified by the combination of the &lt;em&gt;ipAddress&lt;/em&gt; and &lt;em&gt;subnetMask&lt;/em&gt; attributes. Setting &lt;em&gt;allowUnlisted&lt;/em&gt; to &lt;em&gt;false&lt;/em&gt; means that only those individual addresses, or address ranges, explicitly specified will be allowed to make HTTP requests to the website. Setting the &lt;em&gt;allowed&lt;/em&gt; attribute to &lt;em&gt;true&lt;/em&gt; in the child add element indicates that the address and subnet together define an address range that is allowed to access the website. If a request is made to a website from an address outside of the allowed IP address range, then a&amp;nbsp;&lt;em&gt;HTTP 404 Not Found&lt;/em&gt; error is returned as defined in the &lt;em&gt;denyAction&lt;/em&gt; attribute.&lt;/p&gt;
&lt;p&gt;Stay safe out there!&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/Petra-Liljecrantz/Dates/2016/4/common-security-issues-with-a-cms-application/</guid>            <pubDate>Thu, 14 Apr 2016 20:39:16 GMT</pubDate>           <category>Blog post</category></item><item> <title>Differences between scheduled publish and normal publish</title>            <link>https://world.optimizely.com/blogs/Petra-Liljecrantz/Dates/2016/3/differences-between-scheduled-publish-and-normal-publish/</link>            <description>&lt;p&gt;This is the third post on issues I encountered working for Episerver Managed Services and this time it&amp;acute;s about&amp;nbsp;scheduled publish. One question that we got fairly frequent was about the scheduled publish job. Partners had issues of different kind (pages not publishing, cache not working etc.) and it was escalated to us. I find that there isn&amp;acute;t a whole lot documented about scheduled publishing so these are some stuff I learnt directly from the developer team. It covers some differences between a scheduled publish and a normal publish done manually by an editor which publishes the page directly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The normal&amp;nbsp;publish uses the users context while the scheduled publish runs without the users context and thus it skips the access check. This could in theory mean that a page can be scheduled for publish by a user that isn&amp;acute;t supposed to be able to publish.&lt;/li&gt;
&lt;li&gt;The normal&amp;nbsp;publish has access to the HttpContext and the scheduled publish hasn&amp;acute;t, so if a page that&amp;acute;s target for a scheduled publish relies on the HttpContext it&amp;nbsp;will probably&amp;nbsp;have some issues and the publish will most likely&amp;nbsp;fail.&lt;/li&gt;
&lt;li&gt;The normal&amp;nbsp;publish fires off the publish event&amp;nbsp;which will invalidate the built-in cache so that all load balanced servers will go to the database to fetch the new content, the scheduled publish however does not fire off that event so other load balanced servers will not get the new content until the &lt;em&gt;pageCacheSlidingExpiration&amp;nbsp;&lt;/em&gt;has passed (which is by default 12 hours). This setting can be changed in web.config by adding &lt;em&gt;pageCacheSlidingExpiration&amp;nbsp;&lt;/em&gt;anywhere in the &lt;em&gt;applicationSettings&lt;/em&gt;&amp;nbsp;tag within the &lt;em&gt;episerver&lt;/em&gt;&amp;nbsp;tag, like this:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt;&amp;lt;episerver&amp;gt;
    &amp;lt;applicationSettings httpCacheability=&quot;Public&quot; pageCacheSlidingExpiration=&quot;7.00:00:00&quot;...&lt;/code&gt;&lt;/pre&gt;</description>            <guid>https://world.optimizely.com/blogs/Petra-Liljecrantz/Dates/2016/3/differences-between-scheduled-publish-and-normal-publish/</guid>            <pubDate>Tue, 22 Mar 2016 11:54:42 GMT</pubDate>           <category>Blog post</category></item><item> <title>How to keep the integrity of a backup chain</title>            <link>https://world.optimizely.com/blogs/Petra-Liljecrantz/Dates/2016/3/how-to-keep-the-integrity-of-a-backup-chain/</link>            <description>&lt;p&gt;This is the second post about issues I often encountered working for Episerver Managed Services. It&amp;acute;s not an Episerver specific blog post per se, but we often saw&amp;nbsp;this problem and it has to do with developers messing up the integrity of a backup chain. For some people this might be obvious and a no brainer, but like I wrote, it was quite a big problem so people need to learn and be aware of this.&lt;/p&gt;
&lt;h2&gt;The&amp;nbsp;backup chain&lt;/h2&gt;
&lt;p&gt;In any hosting environment, regardless if you have in-house hosting or with a hosting provider such as Episerver Managed Services there are of course&amp;nbsp;backup jobs running to backup an SQL database. A common setup is to take a full backup once a week and differential backups running each day or perhaps a full backup once and then only differential backups each day. Regardless which approach is used it&amp;acute;s important to keep the integrity of the backup chain.&lt;/p&gt;
&lt;h2&gt;The issue&lt;/h2&gt;
&lt;p&gt;All too often partners or customers have access to the production database and performing backups before a deploy. That&amp;acute;s all good and is what should be done, but the developer might not&amp;nbsp;have knowledge about how the backups are run and how a backup chain works, so when they do a backup they do a full backup and are not aware that by&amp;nbsp;&lt;strong&gt;not&lt;/strong&gt;&amp;nbsp;checking the box &lt;strong&gt;Copy-only database&lt;/strong&gt; they are destroying the backup chain causing the database not being able to be restored to the latest differential backup. In the case of trouble and the database have to be restored the previous differential backup can&amp;acute;t be used, it will mess up the database.&lt;/p&gt;
&lt;p&gt;Of course the full backup done before the deploy was made could be used but then the backup chain has to be setup again with an initial full backup. And if the database backup in question has been deleted after the deploy or can&amp;acute;t be used for any other reason then a lot of data would be lost when having to revert back to the latest full backup in the backup chain.&lt;/p&gt;
&lt;h2&gt;The solution&lt;/h2&gt;
&lt;p&gt;Always check the&amp;nbsp;&lt;strong&gt;Copy-only backup&lt;/strong&gt;&amp;nbsp;box when doing a backup before a deploy, as shown here:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/0962df1d8e5147e8a1c2ee549056ab5e.aspx&quot; alt=&quot;Image copyonlycheck.png&quot; /&gt;&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/Petra-Liljecrantz/Dates/2016/3/how-to-keep-the-integrity-of-a-backup-chain/</guid>            <pubDate>Mon, 21 Mar 2016 12:02:54 GMT</pubDate>           <category>Blog post</category></item><item> <title>How to avoid RaiseEvent error on cache invalidation</title>            <link>https://world.optimizely.com/blogs/Petra-Liljecrantz/Dates/2016/3/how-to-avoid-raiseevent-error-on-cache-invalidation/</link>            <description>&lt;p&gt;It&amp;acute;s been a little over six months since I left Episerver and my job as Web Applications Engineer in the group Web Operations in Managed Services. During my time there I just couldn&amp;acute;t find the time to blog about some stuff that I learnt about recurring issues of many different applications written by many different partners.&lt;/p&gt;
&lt;p&gt;I&amp;acute;d thought that I would write some blog posts now instead about the most frequent issues that we handled in Managed Services. This first one will cover errors occuring upon cache invalidation in load balanced environments.&lt;/p&gt;
&lt;h2&gt;Episerver CMS event system&lt;/h2&gt;
&lt;p&gt;It&amp;acute;s well known that&amp;nbsp;Episerver has an event system that sends out messages when a page have been published so the built-in cache gets invalidated and the new content is fetched from the database. This event system is mainly used in load balanced environments or when a separate admin server has been setup.&lt;/p&gt;
&lt;p&gt;I&amp;acute;m not going to dig deep into how it works since there&amp;acute;s a lot of blog posts and help about that, but I&amp;acute;ll cover the basics before addressing the issue we often saw.&lt;/p&gt;
&lt;p&gt;The event system can use UDP or TCP but UDP is the default one and is usually the one that works best without modification. An event system is setup in the web.config.&lt;/p&gt;
&lt;p&gt;Add this code inside the&amp;nbsp;&lt;em&gt;system.serviceModel&lt;/em&gt;&amp;nbsp;tag:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;lt;serviceHostingEnvironment multipleSiteBindingsEnabled=&quot;true&quot; aspNetCompatibilityEnabled=&quot;true&quot;/&amp;gt;
&amp;lt;extensions&amp;gt;
    &amp;lt;bindingElementExtensions&amp;gt;
        &amp;lt;add name=&quot;udpTransportCustom&quot; type=&quot;Microsoft.ServiceModel.Samples.UdpTransportElement, EPiServer.Events&quot;/&amp;gt;
    &amp;lt;/bindingElementExtensions&amp;gt;
&amp;lt;/extensions&amp;gt;
&amp;lt;services&amp;gt;
   &amp;lt;service name=&quot;EPiServer.Events.Remote.EventReplication&quot;&amp;gt;
        &amp;lt;endpoint name=&quot;RemoteEventServiceEndPoint&quot; contract=&quot;EPiServer.Events.ServiceModel.IEventReplication&quot; binding=&quot;customBinding&quot; bindingConfiguration=&quot;RemoteEventsBinding&quot; address=&quot;soap.udp://239.255.255.19:5000/RemoteEventService&quot; /&amp;gt;
    &amp;lt;/service&amp;gt;
&amp;lt;/services&amp;gt;
&amp;lt;client&amp;gt;
    &amp;lt;endpoint name=&quot;RemoteEventServiceClientEndPoint&quot; address=&quot;soap.udp://239.255.255.19:5000/RemoteEventService&quot; binding=&quot;customBinding&quot; bindingConfiguration=&quot;RemoteEventsBinding&quot; contract=&quot;EPiServer.Events.ServiceModel.IEventReplication&quot; /&amp;gt;
&amp;lt;/client&amp;gt;
&amp;lt;behaviors&amp;gt;
    &amp;lt;serviceBehaviors&amp;gt;
        &amp;lt;behavior name=&quot;DebugServiceBehaviour&quot;&amp;gt;
            &amp;lt;serviceDebug includeExceptionDetailInFaults=&quot;true&quot;/&amp;gt;
        &amp;lt;/behavior&amp;gt;
    &amp;lt;/serviceBehaviors&amp;gt;
&amp;lt;/behaviors&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add this inside the&amp;nbsp;&lt;em&gt;bindings&lt;/em&gt;&amp;nbsp;tag:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;lt;customBinding&amp;gt;
    &amp;lt;binding name=&quot;RemoteEventsBinding&quot;&amp;gt;
        &amp;lt;binaryMessageEncoding/&amp;gt;
        &amp;lt;udpTransportCustom multicast=&quot;True&quot;/&amp;gt;
    &amp;lt;/binding&amp;gt;
&amp;lt;/customBinding&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;/h2&gt;
&lt;h2&gt;RaiseEvent error thrown upon cache invalidation&lt;/h2&gt;
&lt;p&gt;Now to the issue and the purpose of this blog post:&lt;/p&gt;
&lt;p&gt;The IP number with a port assigned, &lt;em&gt;239.255.255.19:5000&lt;/em&gt;, is a default UDP broadcast IP and can be left as is for both service and client. The only exception is if the server is hosting multiple EPiServer CMS versions, like CMS 6 R2 and CMS 7.5, then you&amp;acute;ll have to change the port number to 5001 (for example, it can be whatever you want) for either the CMS 6 R2 version or the 7.5 version. This is because from version 7.5 and above the broadcast messages are handled different and if both CMS versions listens to the same port number you&amp;acute;ll get a lot of errors thrown and the cache invalidation isn&amp;acute;t working properly.&lt;/p&gt;
&lt;p&gt;These errors looks like this in New Relic and we saw up to several thousands of these errors in just a couple of hours in some applications.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/85f4fb0d2eef4d15a0d4b21e5412c5e3.aspx&quot; alt=&quot;Image RaiseEventError.png&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;&lt;/h2&gt;
&lt;h2&gt;Same validation key in databases&lt;/h2&gt;
&lt;p&gt;One thing that is also really important to know is that if the production database is created from a backup of the stage database they will invalidate each other&amp;rsquo;s cache since they will share the same key used for validation when a broadcast message arrives. It might not be a major issue that the stage environment for example gets its cache invalidated alongside production, but it&amp;acute;s good to know that it will happen and why. The only way around this is to setup a completly new database for production (or staging if you&amp;acute;d rather work the other way around) and do some migrating of content.&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/Petra-Liljecrantz/Dates/2016/3/how-to-avoid-raiseevent-error-on-cache-invalidation/</guid>            <pubDate>Sun, 20 Mar 2016 16:03:06 GMT</pubDate>           <category>Blog post</category></item></channel>
</rss>