DevEX - reference for building teams, processes, and platforms
Writing Secure SharePoint Code - SharePoint Saturday Toronto
1.
2. Eli Robillard is a seven-time Microsoft SharePoint MVP.
He specializes in SharePoint architecture and building
great teams to manage SharePoint as an enterprise
service platform.
As a thought leader and educator, Eli co-founded the
ASPInsiders in 2003, launched the Toronto SharePoint
User Group in 2006, launched the first free SP Saturday
conference in 2007, was a co-author of Professional
SharePoint 2007 Development and a technical editor of
Professional Professional SharePoint 2010
Development (Wrox Press).
Eli is engaged with PricewaterhouseCoopers to launch
and ensure the operational success of a global internal
SharePoint service. He is based in Toronto, Canada.
E-mail
eli@erobillard.com
Twitter
@erobillard
Blog
weblogs.asp.net/erobillard
8. • Cross-site scripting, SQL InjectionInput validation
• Cookie replay attacks, Network eavesdroppingAuthentication
• Elevation of privilege, Data tampering, Luring attacksAuthorization
• Over-privileged accounts, access to admin interfacesConfiguration management
• Access to data at-rest, data tamperingSensitive data
• Session hijacking, session replay, Man-in-the-middle attacksSession Management
• Poor key managementCryptography
• Form field, cookie, and query string manipulationParameter Manipulation
• Errors reveal implementation, Denial-of-service attacksException Management
• User denies accountability, Attackers cover their tracksAuditing and Logging
9. • Contain attacksCompartmentalize
• A breach should not lead to a greater breachUse least privilege
• Use multiple gatekeepers, do not allow a single point of failureApply defense in depth
• Assume all input is malicious until proven safeDo not trust user input
• Authenticate and authorize as early in the process as possibleCheck at the gate
• Do not provide details to help an attacker understand the mechanismFail securely
• Is the network, host or application the weakest link?Secure the weakest link
• Standards, open libraries, and automation all helpCreate secure defaults
• If you don't use it, remove or disable itReduce the attack surface
11. • Promiscuous headers
• Identifiable UI Elements
It is easy to identify SharePoint sites
• Be aware, some need faster action than others
• JavaScript injection is most common
• IFRAME click-jacking is possible by default
SharePoint is susceptible to known ASP.NET exploits
• Files, pages, cookies and history can be cached on the user's system
• Static assets in the SharePoint hive do not require authorization
• Any web part in the GAC can be used on any site
• Any application page in the hive is accessible from every application and site
• Web and WCF services are visible for all sites
SharePoint is susceptible to SharePoint exploits
22. SPWeb web = site.OpenWeb();
// do stuff with web
SPWeb web = site.OpenWeb();
// do stuff with web
myWeb.Dispose();
using (SPWeb web = site.OpenWeb())
{
// do stuff with web
}
26. // Is the ItemId parameter an Int32?
if(!Int32.TryParse(Request.QueryString["ItemId"],out ItemId))
{
// Exit with an invalid parameter error
// Is the ListId parameter a GUID?
RegexStringValidator val = new RegexStringValidator(@"^{?[dA-Fa-
f]{8}-[dA-Fa-f]{4}-[dA-Fa-f]{4}-[dA-Fa-f]{4}-[dA-Fa-
f]{12}}?$");
// If invalid, this will throw a System.ArgumentException
val.Validate(Request.QueryString["ListId"]);
Guid ListId = new Guid(Request.QueryString["ListId"]);
28. if (HttpContext.Current == null)
{
// parmAbsUrl is an absolute URL in the format "http://server/sites/mySite/"
using (SPSite site = new SPSite(parmAbsoluteUrl))
{
using (SPWeb web = site.OpenWeb(parmAbsoluteUrl))
{
web.AllowUnsafeUpdates = true;
// Update SharePoint objects here
web.AllowUnsafeUpdates = false;
}
}
}
else // HttpContext.Current has a value
{
SPUtility.ValidateFormDigest();
// Update SharePoint objects here
}
29. [DllImport("advapi32.dll")]
public static extern uint EventActivityIdControl(
uint controlCode, ref Guid activityId);
public const uint EVENT_ACTIVITY_CTRL_GET_ID = 1;
// …
// And then use it in code like this:
try { // code block goes here }
catch {
Guid g = Guid.Empty;
EventActivityIdControl(EVENT_ACTIVITY_CTRL_GET_ID, ref g);
this.Controls.Add(new Label {
Text = string.Format("An error occurred with Correlation ID {0}", g)
});
}
30. public string NumberArray {
// Require format: 1,2,3,4
get{return _numberArray;}
set{
string [] arr = value.split(',');
foreach (string item in arr) {
int i;
if(!int.TryParse(item,out i))
throw new WebPartPageUserException("The item
""+item+"" is not a valid number");
}
_numberArray=value;
}
}
31.
32. SPWeb web = SPContext.Current.Web;
try
{
// Verify this is a postback from a valid Application Page
SPUtility.ValidateFormDigest();
// Verify that the user has a valid permission before elevating
if (web.DoesUserHavePermissions(SPBasePermissions.ManageWeb))
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
// Read data using the SharePoint Object Model here
});
}
}
33. // Update a SharePoint property
using (SPSite elevatedSite =
LitwareSecurity.SharePoint.Security.GetElevatedSite(web.Site)
{
// Update data using SharePoint object model here.
}
The secret sauce: GetElevatedSite first tries
site.SystemAccount.UserToken.
If that doesn’t work it falls back to RWEP() to
GetSystemToken().
It then returns an elevated SPSite using this
token.
Get the source: http://www.danlarson.com/elevated-privilege-with-spsite/
34. // Call a non-SharePoint resource
using (HostingEnvironment.Impersonate())
{
// Call an external resource using the credentials of
// the Application Pool ID here
}
40. Scope Pertains To
Site Collection * A SharePoint Site Collection
Web * A SharePoint Web Site
List * A SharePoint list
Search The SharePoint Search Service
Workflow The Windows Azure Workflow Service
Taxonomy The SharePoint Taxonomy Service
BCS Read access to BCS service data sources
41. App
permission name
SharePoint
permission name
Permissions
Read Reader View Items, Open Items, View Versions,
Create Alerts, Use Self-Service Site Creation,
View Pages
Write Contributor Read-Only permissions, plus:
Add Items, Edit Items, Delete Items, Delete
Versions, Browse Directories, Edit Personal
User Information, Manage Personal Views,
Add/Remove Personal Web Parts, Update
Personal Web Parts
Manage Designer Write permissions, plus:
Manage Lists, Add and Customize Pages,
Apply Themes and Borders, Apply Style
Sheets
FullControl Full Control All permissions.
42. Policy Conditions
User-only Policy Content database authorization checks succeed if the User
has sufficient permissions to perform the action.
App-only Policy Content database authorization checks succeed if the App
has sufficient permissions, whether or not the current user (if
there is a current user) has the same permissions.
User and App Policy Content database authorization checks succeed only if both
the current User and the App have sufficient permissions to
perform the actions that the App is designed to perform.
This is required to act on behalf of the user when the App is
hosted in a Remote Web and not an App Web.
48. Join our local users
groupsToronto SharePoint Users Group
http://www.tspug.com/
Toronto SharePoint Business Users
Group
http://www.meetup.com/TSPBUG/
Thanks to DakshKhullar for suggesting improvements to this presentation
Where you do not have control, be aware
Responsible, Accountable, Consulted, Informed Sources:Improving Web Application Security, Threats and Countermeasures, Microsoft Press, p. lxxxiImproving .NET Application Performance and Scalability, Microsoft Developer Network, http://msdn.microsoft.com/en-us/library/ff648148.aspx
When rating the threats, disregard whether or not special knowledge might be needed to discover the vulnerability. Assume that your attacker has full knowledge of the system. Describe MS10-070 (a zero day exploit of the application pool identity, allowing the attacker access to the web root including web.config and the SharePoint hive).
Ibid., pp. 13-43
Source: Ibid., p. 11
Click-jacking (a luring attack) is disabled in SharePoint 2013 by default. “Frame-breaking” Javascript code works equally well to prevent wrapping the page in an IFRAME. Note that Apps run in IFRAMES so you wouldn’t protect SP2013 Apps this way, only the SharePoint WFEs. Note that the “HTTP Only” cookie setting breaks out-of-box workflow as these use the InfoPath-style forms rather than WebForms. The error message is, “The form cannot be displayed because the use of session cookies has been disabled in the current browser settings. In order to load the form, session cookies must be allowed.”
Minimum required accounts: http://technet.microsoft.com/en-us/library/ee662513.aspx Reference: Account permissions and security settings in SharePoint 2013http://technet.microsoft.com/en-us/library/cc678863.aspx WSS_ADMIN_WPG, WSS_WPG and other group permissions Registry, File System (including hosts) http://technet.microsoft.com/en-us/library/ee662513.aspx
Plan for App Authentication in SharePoint 2013http://technet.microsoft.com/en-us/library/jj219806.aspx
External Data Reference (BCS): http://msdn.microsoft.com/en-us/library/ff798353.aspxManaged account reference: http://blog.falchionconsulting.com/?s=%22managed+accounts%22
Authorization and authentication for apps in SharePoint 2013http://msdn.microsoft.com/en-us/library/fp142384.aspxWhile presenting to Bermuda SharePoint User Group, Craig Lussier asked: “Where it would be best to store configuration if you are a vendor and want to release a web part to check for membership in a particular AD group before executing an operation (e.g. prior to creating a user in AD)?” While web.config is the easiest place to name your AD group, a better solution would be to create a Central Admin page that would let you configure the web part per site collection, and store the property in the Site Collection Root Web’s property bag. Then the web part could look the value up and if it existed, would execute; or if the propety did not exists, the WP would “know” it is not allowed to be executed in that context.
HP WebInspect is popular but results are mixed with SharePoint sites. MSR’s Gatekeeper project is a promising static analysis tool for JavaScript but no tools implementing its principles appear available: http://research.microsoft.com/en-us/projects/gatekeeper/
Let’s start with an easy one
Based on the following post Martin Laplante (IceFire) suggested that this technique may have performance implications: http://www.alaindeklerk.com/checking-user-permissions-doesuserhavepermissions-vs-catchaccessdeniedexception/ However the alternative – try {} the operation and catch {} it if it fails – does not assert any security before executing the actual operation. Therefore it is a great technique for trapping exceptions before they reach the user or to display a friendly “Access Denied” message, but does not achieve the goal: to confirm that the user has an appropriate permission before running a view or update operation on a SharePoint object.
Anti-Cross Site Scripting Libraryhttp://msdn.microsoft.com/en-us/security/aa973814.aspxReference: Microsoft Anti-Cross Site Scripting Library v1.5: Protecting the Contoso Bookmark Pagehttp://msdn.microsoft.com/en-us/library/aa973813.aspx
Great posts on AllowUnsafeUpdates by Hristo Pavlov: http://hristopavlov.wordpress.com/2008/05/16/what-you-need-to-know-about-allowunsafeupdates/ http://hristopavlov.wordpress.com/2008/05/21/what-you-need-to-know-about-allowunsafeupdates-part-2/
Get the source to make this work from Dan Larsen: http://www.danlarson.com/elevated-privilege-with-spsite/ Or paste it from here! using System;using Microsoft.SharePoint; namespace LitwareSecurity{ /// <summary>A class for working with elevated privilege</summary> public static class SpSecurityHelper { /// <summary>Returns an elevated site</summary> /// <param name="theSite"> /// The site that you want an elevated instance of. /// You must dispose of this object unless it is part of SPContext.Current. /// </param> /// <returns>An elevated site context.</returns> /// <remarks>Be sure to dispose of objects created from this method.</remarks> public static SPSite GetElevatedSite(SPSitetheSite) { varsysToken = GetSystemToken(theSite); return new SPSite(theSite.ID, sysToken); } /// <summary>Gets a UserToken for the system account.</summary> /// <param name="site"></param> /// <returns>A usertoken for the system account user./returns> /// <remarks>Use this token to impersonate the system account</remarks> public static SPUserTokenGetSystemToken(SPSite site) { site.CatchAccessDeniedException = false; try { return site.SystemAccount.UserToken; } catch (UnauthorizedAccessException) { SPUserTokensysToken = null; // Only use runwithelevated to grab the system user token. SPSecurity.RunWithElevatedPrivileges( delegate() { using (SPSitelolcatKiller = new SPSite(site.ID)) { sysToken = lolcatKiller.SystemAccount.UserToken; } } ); return sysToken; } } }}
Source: SPC205, Ted Pattison (with changes: Cloud-hosted clarified as both Provider and Auto-hosted Apps)
Source: SPS030, Todd Baginski
Reference:App Permissions in SharePoint 2013 http://msdn.microsoft.com/en-us/library/fp142383.aspxList Elements (including out-of-box Base Type IDs) http://msdn.microsoft.com/en-us/library/ms415091.aspx
Reference: Addressing same-origin policy limitations in apps for Office: http://msdn.microsoft.com/en-us/library/fp123589.aspx Configuring SharePoint On-premise Deployment for Apps: http://blogs.technet.com/b/mspfe/archive/2013/01/31/configuring-sharepoint-on-premise-deployments-for-apps.aspx