/// <summary> /// Performs an audit and returns a list of audit issues /// </summary> public static IEnumerable <SecurityAuditItem> GetAuditIssues(HttpRequestBase request = null) { // 1. Ensure that SSL is working on the admin site. An issue with LiveServer can cause SSL not to function. if (!CommonLogic.IsSecureConnection()) { yield return new SecurityAuditItem() { Message = "Your Admin site is not currently using SSL. This can allow data being sent to and from the admin site to be read in transit. <a href='http://www.aspdotnetstorefront.com/linkmanager.aspx?topic=10000manual&type=ssl' target='_blank'>Click Here</a> to learn how to enable SSL.", ItemType = SecurityAuditItemType.Security } } ; // 2. Check for path element containing /admin/. We do not allow Admin sites to be located at the default /admin/ path. Too easy to guess. if (request != null && request.Path.IndexOf("/admin/", StringComparison.InvariantCultureIgnoreCase) != -1) { yield return new SecurityAuditItem() { Message = "The URL to your Admin site contains '/admin/'. This does not follow our <a href='http://www.aspdotnetstorefront.com/linkmanager.aspx?topic=10000manual&type=securitybestpractices' target='_blank'>security best practices</a>. Please immediately rename the Admin folder, and restart the website.", ItemType = SecurityAuditItemType.Security } } ; // 3. Remove or change [email protected]. Cannot use the default credentials long-term. if (new Customer("*****@*****.**").EMail == "*****@*****.**") { yield return new SecurityAuditItem() { Message = "The default user '*****@*****.**' is a registered user on this website. <a href='customers.aspx?filter.0.0=admin%40aspdotnetstorefront.com'>Click Here</a> to edit this user.", ItemType = SecurityAuditItemType.Security } } ; // 4. Check MailMe_Server AppConfig Setting. Cannot Allow blank MailMe_Server AppConfig. var mailServerConfig = AppLogic.AppConfig("MailMe_Server"); if (string.IsNullOrWhiteSpace(mailServerConfig) || mailServerConfig.Equals(AppLogic.ro_TBD, StringComparison.InvariantCultureIgnoreCase) || mailServerConfig.Equals("MAIL.YOURDOMAIN.COM", StringComparison.InvariantCultureIgnoreCase)) { yield return new SecurityAuditItem() { Message = "The 'MailMe_Server' Setting is not properly configured. Click <a href=\"mailingtest.aspx\">here</a> to configure mail settings.", ItemType = SecurityAuditItemType.Security } } ; // 5. Check for admin\assetmanager folder. Should be deleted. if (Directory.Exists(CommonLogic.SafeMapPath("assetmanager"))) { yield return new SecurityAuditItem() { Message = "The obsolete folder 'assetmanager' exists in your site's Admin folder, and can present a security risk. Please delete this folder and its contents.", ItemType = SecurityAuditItemType.Security } } ; // 6. Check for match between path and AdminDir. Verify that AdminDir is set correctly. if (request != null && request.Path.IndexOf(string.Format("/{0}/", AppLogic.AppConfig("AdminDir")), StringComparison.InvariantCultureIgnoreCase) == -1) { yield return new SecurityAuditItem() { Message = "The URL to your Admin site does not match the 'AdminDir' Setting, which can lead to disclosure of your Admin URL. Please update the 'AdminDir' Setting, using the 'Configuration -> Settings' menu.", ItemType = SecurityAuditItemType.Security } } ; if (AppLogic.TrustLevel == AspNetHostingPermissionLevel.Unrestricted || AppLogic.TrustLevel == AspNetHostingPermissionLevel.High) { var webConfig = WebConfigurationManager.OpenWebConfiguration("~"); // 7. Check for debug=true in web.config. Should be false on a live site. var compilation = (CompilationSection)webConfig.GetSection("system.web/compilation"); if (compilation.Debug == true) { yield return new SecurityAuditItem() { Message = "The 'compilation' element in web.config is set to 'debug=true'. Please set it to 'debug=false' to improve site performance.", ItemType = SecurityAuditItemType.Security } } ; // 8. Check encryption on web.config. Must be encrypted as the last step before going Live. var appSettings = webConfig.GetSection("appSettings"); if (!appSettings.SectionInformation.IsProtected) { yield return new SecurityAuditItem() { Message = "The web.config file is not encrypted. This does not follow our <a href='http://www.aspdotnetstorefront.com/linkmanager.aspx?topic=10000manual&type=securitybestpractices' target='_blank'>security best practices</a>. Please use the <a href='wizard.aspx'>Site Setup Wizard</a> to encrypt the web.config file before going Live.", ItemType = SecurityAuditItemType.Security } } ; // 9. Check write permissions on web.config. Must have write-permission to encrypt, then have read-only permission after encryption. if (FileIsWriteable(CommonLogic.SafeMapPath("~/web.config"))) { yield return new SecurityAuditItem() { Message = "The file permission on web.config allows for write-access. This does not follow our <a href='http://www.aspdotnetstorefront.com/linkmanager.aspx?topic=10000manual&type=securitybestpractices' target=\"_blank\">security best practices</a>. Please set the web.config file as read-only before going Live.", ItemType = SecurityAuditItemType.Security } } ; // 10. Check non-write permissions on root. Cannot allow root folder to have write permission. if (FolderIsWriteable(CommonLogic.SafeMapPath("~/"))) { yield return new SecurityAuditItem() { Message = "The root directory of your website allows write-access. Please remove write-access before going Live. <a href='http://www.aspdotnetstorefront.com/linkmanager.aspx?topic=10000manual&type=golive' target='_blank'>Read more</a>", ItemType = SecurityAuditItemType.Security } } ; // 11. Check for customErrors Mode=Off in web.config. Should be RemoteOnly or On on a Live site. var customErrors = (CustomErrorsSection)webConfig.GetSection("system.web/customErrors"); if (customErrors.Mode == CustomErrorsMode.Off) { yield return new SecurityAuditItem() { Message = "The 'customErrors' element in web.config is set to 'off'. Please set it to 'on' before going Live. <a href='http://www.aspdotnetstorefront.com/linkmanager.aspx?topic=10000manual&type=golive' target=\"_blank\">Read more</a>", ItemType = SecurityAuditItemType.Security } } ; } // 12. DotFeed is installed but not enabled. if (AppConfigManager.AppConfigExists("DotFeed.AccessKey") && string.IsNullOrEmpty(AppLogic.AppConfig("DotFeed.AccessKey"))) { yield return new SecurityAuditItem() { Message = "DotFeed is installed but not enabled, <a href=\"https://manage.dotfeed.com\" target=\"_blank\">click here</a> to configure DotFeed", ItemType = SecurityAuditItemType.Configuration } } ; // 13. Site is using the default Search Engine Meta Title, Description, and Keywords tags. if (AppLogic.AppConfig("SE_MetaTitle").ContainsIgnoreCase("Enter your site title here") || AppLogic.AppConfig("SE_MetaDescription").ContainsIgnoreCase("enter your site description here") || AppLogic.AppConfig("SE_MetaKeywords").ContainsIgnoreCase("enter your site keywords here")) { yield return new SecurityAuditItem() { Message = "Your site is using the default Search Engine Meta Title & Description tags, <a href=\"wizard.aspx#trSEO\">click here</a> to update.", ItemType = SecurityAuditItemType.Configuration } } ; // 14. Time to change the encrypt key var nextKeyChangeDate = DateTime.MinValue; if (AppLogic.AppConfigBool("StoreCCInDB") && DateTime.TryParse(AppLogic.AppConfig("NextKeyChange"), out nextKeyChangeDate)) { if (nextKeyChangeDate < DateTime.Now) { yield return new SecurityAuditItem() { Message = "Time To Change Your Encrypt Key!", ItemType = SecurityAuditItemType.Security } } ; } }
/// <summary> /// Performs an audit and returns a list of audit issues /// </summary> public static IEnumerable <SecurityAuditItem> GetAuditIssues(HttpRequestBase request = null) { // 1. Ensure that SSL is working on the admin site. An issue with LiveServer can cause SSL not to function. if (!CommonLogic.IsSecureConnection()) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.SSL"), ItemType = SecurityAuditItemType.Security } } ; // 2. Check for path element containing /admin/. We do not allow Admin sites to be located at the default /admin/ path. Too easy to guess. if (request != null && request.Path.IndexOf("/admin/", StringComparison.InvariantCultureIgnoreCase) != -1) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.PathElement"), ItemType = SecurityAuditItemType.Security } } ; // 3. Remove or change [email protected]. Cannot use the default credentials long-term. if (new Customer("*****@*****.**").EMail == "*****@*****.**") { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.DefaultAdmin"), ItemType = SecurityAuditItemType.Security } } ; // 4. Check MailMe_Server AppConfig Setting. Cannot Allow blank MailMe_Server AppConfig. var mailServerConfig = AppLogic.AppConfig("MailMe_Server"); if (string.IsNullOrWhiteSpace(mailServerConfig) || mailServerConfig.Equals(AppLogic.ro_TBD, StringComparison.InvariantCultureIgnoreCase) || mailServerConfig.Equals("MAIL.YOURDOMAIN.COM", StringComparison.InvariantCultureIgnoreCase)) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.MailServer"), ItemType = SecurityAuditItemType.Security } } ; // 5. Check for admin\assetmanager folder. Should be deleted. if (Directory.Exists(CommonLogic.SafeMapPath("assetmanager"))) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.AssetManager"), ItemType = SecurityAuditItemType.Security } } ; // 6. Check for match between path and AdminDir. Verify that AdminDir is set correctly. if (request != null && request.Path.IndexOf(string.Format("/{0}/", AppLogic.AppConfig("AdminDir")), StringComparison.InvariantCultureIgnoreCase) == -1) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.AdminDir"), ItemType = SecurityAuditItemType.Security } } ; if (AppLogic.TrustLevel == AspNetHostingPermissionLevel.Unrestricted || AppLogic.TrustLevel == AspNetHostingPermissionLevel.High) { var webConfig = WebConfigurationManager.OpenWebConfiguration("~"); // 7. Check for debug=true in web.config. Should be false on a live site. var compilation = (CompilationSection)webConfig.GetSection("system.web/compilation"); if (compilation.Debug == true) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.Debug"), ItemType = SecurityAuditItemType.Security } } ; // 8. Check encryption on web.config. Must be encrypted as the last step before going Live. var appSettings = webConfig.GetSection("appSettings"); if (!appSettings.SectionInformation.IsProtected) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.Encryption"), ItemType = SecurityAuditItemType.Security } } ; // 9. Check write permissions on web.config. Must have write-permission to encrypt, then have read-only permission after encryption. if (FileIsWriteable(CommonLogic.SafeMapPath("~/web.config"))) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.WebConfigWritable"), ItemType = SecurityAuditItemType.Security } } ; // 10. Check non-write permissions on root. Cannot allow root folder to have write permission. if (FolderIsWriteable(CommonLogic.SafeMapPath("~/"))) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.RootWritable"), ItemType = SecurityAuditItemType.Security } } ; // 11. Check for customErrors Mode=Off in web.config. Should be RemoteOnly or On on a Live site. var customErrors = (CustomErrorsSection)webConfig.GetSection("system.web/customErrors"); if (customErrors.Mode == CustomErrorsMode.Off) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.CustomErrors"), ItemType = SecurityAuditItemType.Security } } ; } // 12. DotFeed is installed but not enabled. if (AppConfigManager.AppConfigExists("DotFeed.AccessKey") && string.IsNullOrEmpty(AppLogic.AppConfig("DotFeed.AccessKey"))) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.DotFeedNotEnabled"), ItemType = SecurityAuditItemType.Configuration } } ; // 13. Site is using the default Search Engine Meta Title, Description, and Keywords tags. if (AppLogic.AppConfig("SE_MetaTitle").ContainsIgnoreCase("Enter your site title here") || AppLogic.AppConfig("SE_MetaDescription").ContainsIgnoreCase("enter your site description here") || AppLogic.AppConfig("SE_MetaKeywords").ContainsIgnoreCase("enter your site keywords here")) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.splash.aspx.security.MetaTagsNotSet"), ItemType = SecurityAuditItemType.Configuration } } ; // 14. Time to change the encrypt key var nextKeyChangeDate = DateTime.MinValue; if (AppLogic.AppConfigBool("StoreCCInDB") && DateTime.TryParse(AppLogic.AppConfig("NextKeyChange"), out nextKeyChangeDate)) { if (nextKeyChangeDate < DateTime.Now) { yield return new SecurityAuditItem() { Message = AppLogic.GetString("admin.default.ChangeEncryptKey"), ItemType = SecurityAuditItemType.Security } } ; } }