Walter.BOM Namespace
Walter.Web.FireWall Namespace
ASP-WAF Web application firewall for .Net 6, .Net 5, .Net Standard 2.1 and .Net Core 3.x

Interactions Structure

Interactions that the user had with a rendered page (only applicable when you use UserDiscovery)

Namespace:  Walter.Web.FireWall
Assembly:  Walter.Web.FireWall (in Walter.Web.FireWall.dll)

Syntax


public struct Interactions

Remarks


Interactions data structure contains data that reflects user interaction with a rendered razor page. ///

Examples


The User discovery is initiated via a JavaScript call in your razor page. the below sample shows how you could set this up.
inject JavaScript from the same constant used in the rout of the ValidateUser endpoint
<script src="@Url.Content(Links.UserEndpointJavaScript)"></script>
Register interactions of the user
[HttpGet]
   [Route(Links.UserEndpointJavaScript)]
   [AllowAnonymous, Ignore(Walter.Web.FireWall.Filters.FireWallGuardActions.EmbeddedResources)]
   [NoCache]
   public FileContentResult ValidateUser()
   {
       //use the ID to force reloading the script after the user has logged in or logged off//as the firewall will create a different script for logged in users.try
       {
           if (_fireWall.TryGetValidateUserJavaScript(page: _page, out var javaScript))
           {
               var file = File(fileContents: javaScript, contentType: "text/javascript");
               file.LastModified = DateTime.UtcNow;
               file.FileDownloadName = _page.OriginalUrl.AbsoluteUri;
               return file;
           }
           else
           {
               _logger?.Lazy().LogWarning("ValidateUser javascript generation failed for {Page}", _page.ToString());
               javaScript = System.Text.UTF8Encoding.UTF8.GetBytes($"console.log('could not generate userValidation')");
               return File(fileContents: javaScript, contentType: "text/javascript");
           }
       }
       catch (ArgumentException e)
       {
           _page.Exception = e;

           _fireWall.LogException<RunTimeErrors>(RunTimeErrors.ArgumentNullException, e, "Missing a configuration element or using wrong release for your deployment");
           var javaScript = System.Diagnostics.Debugger.IsAttached
               ? System.Text.UTF8Encoding.UTF8.GetBytes($"console.log('could not generate userValidation due to {e.Message}')")
               : System.Text.UTF8Encoding.UTF8.GetBytes($"//Validate log {DateTime.Now} for errors and update settings");
           return File(fileContents: javaScript, contentType: "text/javascript");
       }
       catch (Exception e)
       {
           _page.Exception = e;

           _fireWall.LogException<RunTimeErrors>(RunTimeErrors.ArgumentNullException, e, $"User type discovery will not work as good as it could please fix {e.Message}");
           var javaScript = System.Text.UTF8Encoding.UTF8.GetBytes($"console.log('could not generate userValidation due to {e.Message}')");
           return File(fileContents: javaScript, contentType: "text/javascript");
       }
       finally
       {
           _logger?.Lazy().LogDebug("ValidateUser called");
       }
   }

   [HttpPost, Route(Links.BeaconPoint), AllowAnonymous]
   [CrossSite, Ignore(skip: FireWallGuardActions.ALL & ~FireWallGuardActions.RejectCrossSiteRequests)]
   [ModelFilter(associations : RequestersAssociations.InCurrentPage
              , generateIncident : false
              , pageGroupPropertyName :Walter.Web.FireWall.Beacon.PageRequestGroupIdModelCode)]
   public StatusCodeResult Beacon(string model)
   {
       if (!ModelState.IsValid)
       {
           _logger?.Lazy().LogInformation("beacon: failed has {errors} errors", ModelState.ErrorCount);
           return this.Ok();//no need to make a fuss
       }

       if (!string.IsNullOrEmpty(model))
       {
           var beacon = JsonConvert.DeserializeObject<Beacon>(model);
           _fireWall.ModelIsValid(pageContext: _page, model: beacon, out var errors);
           if (errors.Sum(s => s.BlockingSeverityScore) < 100)
           {
               _fireWall.LogPageRequest(beacon, _page);
           }
           else
           {
               foreach (var error in errors)
               {
                   _logger?.Lazy().LogInformation("beacon: {warn}", error);
               }
           }
       }
       return this.Ok();
   }

   [HttpPost]
   [AllowAnonymous]
   [Route(Links.IsUserEndpoint)]
   [CrossSite, Ignore(skip: FireWallGuardActions.ALL & ~FireWallGuardActions.RejectCrossSiteRequests)]
   [ModelFilter(Associations = RequestersAssociations.InCurrentPage, GenerateIncident = false)]
   public StatusCodeResult UserDiscovery([FromBody] Discovery model)
   {
       if (model is null)
       {
           _logger?.Lazy().LogDebug("user discovery called but the model field or data types are not compatible, please wait, update the model to fix the users discovery javascript");
           return this.NoContent();
       }
       else
       {
           _fireWall.ModelIsValid(pageContext: _page, model: model, out var errors);
           if (errors.Sum(s => s.BlockingSeverityScore) < 100)
           {
               _fireWall.LogPageRequest(model, _page);
               return Ok();
           }
           else
           {
               _logger?.Lazy().LogInformation("An attempt was made to send a tampered model to {url}", _page.OriginalUrl.AbsoluteUri);
               if (errors.Sum(s => s.BlockingSeverityScore) > 100)
               {
                   var fwu = _page.User.AsFirewallUser();
                   using (var scope = _logger?.BeginScope<string>($"User {fwu.Id} from {fwu.IPAddress} tampered with the model send back to {Links.IsUserEndpoint} and triggered {errors.Count} warnings"))
                   {
                       for (var i = 0; i < errors.Count; i++)
                       {
                           _logger?.Lazy().LogInformation("incident:{count} reason:{reason} context:{context} weight:{weight}", i + 1, errors[i].Reason, errors[i].BlockingContext, errors[i].BlockingSeverityScore);
                       }
                   }
                   //tamper detected so return a 404
                   return this.NotFound();
               }
               //model data is not valid, could be tampered but could also just be not containing required values
               return this.BadRequest();
           }
       }
   }

   [HttpPost, Route(Links.SiteMapEndPoint)]
   [CrossSite(useDefaultRedirect: false), Ignore(skip: FireWallGuardActions.ALL & ~FireWallGuardActions.RejectCrossSiteRequests)]
   [ModelFilter(Associations = RequestersAssociations.InCurrentPage, GenerateIncident =false)]
   public StatusCodeResult SiteMap([FromBody] SiteMapDiscovery model)
   {
       _logger?.Lazy().LogDebug("Url SiteMapDiscovery called ");

       //return await base.SiteMap(model);if (model is null)return NoContent();else
       {
           //The firewall will use predictive navigation for user as well as use it in web-statistics to show choices made by the user
           _fireWall.LogSiteMap(_page, model);
           return Ok();
       }
   }