Skip to content

Latest commit

 

History

History
144 lines (97 loc) · 10.2 KB

security.md

File metadata and controls

144 lines (97 loc) · 10.2 KB

✔ Security

Overview

Web security is a very important topic for anyone who wants to keep their data safe. Smartstore offers ways to restrict access to data:

  • An extensible, hierarchically organized permissions system, where permissions are assigned to customer roles, which are then assigned to customers.
  • Customer roles (including assigned permissions) can automatically be assigned to customers by rule sets.
  • IAclRestricted marks an entity with restricted access rights. Only customers assigned to specific customer groups can see or access it.

Further security tools available are:

  • Anti-forgery token
  • Captcha
  • Honeypot

Permissions tree

Permissions are organized hierarchically in the form of a tree. A permission is granted when it has either granted itself or one of its parent permissions. The same applies to a permission that is explicitly not permitted. In this way, entire groups of permissions can be activated via a parent permission, where child permissions inherit from any ancestor. Therefore, a permission can have four statuses:

Status Representation
Allow allow
Disallow disallow
Inherited allow inherited allowed
Inherited disallow inherited disallow

Example of a permissions tree (partial view)

Authorization

Use the IPermissionService to check whether a given permission is granted to a customer. It expects strings as the name of the permission to be checked. Several constants are provided through the Permissions class for this purpose.

await _permissionService.AuthorizeAsync(Permissions.System.ScheduleTask.Execute);

Action methods use the PermissionAttribute instead of IPermissionService.

[Permission(Permissions.Catalog.Product.Read)]
public async Task<IActionResult> Edit(int id)
{
    //...
}

Use the NeverAuthorizeAttribute when the access to the requested endpoint is always permitted. For instance, the action method of the login page is decorated with this attribute.

An AccessDeniedException is thrown when the permission is not granted. In case of an AJAX request, a message notification is shown, and an alert is returned if a HTML response is expected, or a JSON object otherwise.

Add custom permissions

The permission system can be extended to include custom permissions using the IPermissionProvider. See the DevToolsPermissionProvider example. It is recommended to use singular for permission names and define a root permission Self that doesn't contain any dots by convention:

{% code title="MegaSearch root permission" %}

public const string Self = "megasearch";

{% endcode %}

The localization is done via string resources and by convention. The string resource key is Permissions.DisplayName.<PermissionName> for the core and Modules.Permissions.DisplayName.<PermissionName> for modules. In most cases only the root permission Self is localized because other permissions are already localized by the core like read, update, execute etc. See PermissionService._displayNameResourceKeys for a complete list.

{% hint style="info" %} Module permissions are automatically added when the module is installed and removed when uninstalling the module. Module developers do not need to do anything else here.

TIP: For an IMenuProvider such as the AdminMenuProvider, one or more permissions can be applied via MenuItemBuilder.PermissionNames. The related link in the admin menu is only displayed if the admin has been granted permission. {% endhint %}

Access control list (ACL)

An entity supports restricted access rights when it implements IAclRestricted. It allows limiting an entity to certain customer roles. Only customers who are assigned to one of the associated customer roles can see the product, the category, the menu item, etc.

Use IAclService to check whether the customer has the right to access an entity. If you only want to load those entities from the database the customer has access to, use the ApplyAclFilter extension method.

Use IAclService.ApplyAclMappingsAsync when you want to modify the access rights of a customer to an entity. This is typically done when the entity is updated on its edit page.

Protection tools

Anti-Forgery token

To help prevent CSRF attacks, ASP.NET Core uses anti-forgery tokens, also called request verification tokens. Such a token is automatically created if the HTML form tag uses at least one asp-* attribute and the form is processed by the ASP.NET Core TagHelper accordingly.

<form asp-action="Configure">

In all other cases, Html.AntiForgeryToken() must be explicitly called inside the view for the token to be rendered.

Data grids also create the token automatically but only if the property allowEdit or allowRowSelection is true. Only in these cases the data grid has its own HTML form:

<datagrid id="myentity-grid" allow-row-selection="true" allow-edit="true">
    @* ... *@
</datagrid>

Otherwise the IgnoreAntiforgeryTokenAttribute must be used on the server side to suppress the validation of the token and avoid errors due to a missing token.

For AJAX operations via smartstore.ajax.js or jQuery the token is also generated automatically. Only if a HTML form is created from scratch, the token must be included as well:

{% code title="Create and submit a form" %}

var form = '<form id="MyHtmlForm" action="' + $(this).data('url') + '" method="post">';
form += '<input type="hidden" name="__RequestVerificationToken" value="@Html.GetAntiforgeryToken()">';
form += '</form>';
$('body').append(form);
$('#MyHtmlForm').submit();

{% endcode %}

{% hint style="info" %} Html.GetAntiforgeryToken() renders the anti-forgery token server-side. window.getAntiforgeryToken() returns the token using JavaScript. {% endhint %}

Captcha

Decorate an action method with the ValidateCaptchaAttribute to prevent malicious software from accessing your endpoint. The attribute uses the widely used Google reCAPTCHA for protection. CaptchaTagHelper renders the Google widget in your view.

<captcha sm-enabled="Model.DisplayCaptcha" class="form-group" />

Honeypot

"Honeypots" can be used to prevent robots from posting or manipulating HTML forms. The ValidateHoneypotAttribute redirects back to the current page if an HTML form has been modified by a bot. HoneypotTagHelper renders the required form element in your view.

<honeypot sm-enabled="true" />

Others

In addition to those already mentioned, there are a few other attributes with similar access-restricting functions.

Filter attribute Description
AuthorizeAdmin * Checks whether the current user has the permission to access the administration backend.
AuthorizeShopAccess Checks whether the current user has the permission to access the shop.
DisallowRobot Disallows robots to access an endpoint.
RequireSsl A marker filter indicating that the current request should be received over HTTPS (if the policies allow this).
ValidateAdminIpAddress * Validates the IP address of the user requesting access and match it against a list of allowed IP addresses.

* if your controller inherits from AdminController, this attribute is automatically set and your controller is protected accordingly.