From f8d3bd9555cd719d13a2cc70f3742d55744d9d05 Mon Sep 17 00:00:00 2001 From: Johnny Tordgeman Date: Sun, 16 Sep 2018 11:53:34 +0300 Subject: [PATCH 01/28] Version 2.7.1 --- PerimeterXModule/Properties/AssemblyInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PerimeterXModule/Properties/AssemblyInfo.cs b/PerimeterXModule/Properties/AssemblyInfo.cs index 2ec990a..5f2e0e1 100644 --- a/PerimeterXModule/Properties/AssemblyInfo.cs +++ b/PerimeterXModule/Properties/AssemblyInfo.cs @@ -23,5 +23,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.7.0")] -[assembly: AssemblyFileVersion("2.7.0")] +[assembly: AssemblyVersion("2.7.1")] +[assembly: AssemblyFileVersion("2.7.1")] From 832e008e53964a0b38e9f36f4ad617ffb9072062 Mon Sep 17 00:00:00 2001 From: SaraLumelsky <37770740+SaraLumelsky@users.noreply.github.com> Date: Thu, 20 Sep 2018 11:25:14 +0300 Subject: [PATCH 02/28] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1206e53..0696c87 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,8 @@ Add site specific configuration (configuration level) appId="" apiToken="" cookieKey="" - monitorMode="false" - blockingScore="70" + monitorMode="true" + blockingScore="100" > @@ -134,11 +134,11 @@ Example below: ``` #### Changing the Minimum Score for Blocking -**default:** 70 +**default:** 100 ```xml ... - blockingScore="70" + blockingScore="100" ... ``` @@ -322,7 +322,7 @@ Set this flag to false to disable monitor mode ```xml ... - monitorMode="false" + monitorMode="true" ... ``` **default:** true From b802851ff7f3f1ca8cbefd052a02752f662a8c77 Mon Sep 17 00:00:00 2001 From: pxadmin Date: Sun, 21 Oct 2018 14:09:53 +0300 Subject: [PATCH 03/28] Changed the block template to work when encoutering errors in FP mode --- .../Internals/Templates/block_template.mustache | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/PerimeterXModule/Internals/Templates/block_template.mustache b/PerimeterXModule/Internals/Templates/block_template.mustache index 900df7c..0fcbd6c 100644 --- a/PerimeterXModule/Internals/Templates/block_template.mustache +++ b/PerimeterXModule/Internals/Templates/block_template.mustache @@ -151,8 +151,21 @@ window._pxUuid = '{{uuid}}'; window._pxHostUrl = '{{{hostUrl}}}'; - - + {{#jsRef}} From c77236ef8c133a0895210e00233f29e6d230d703 Mon Sep 17 00:00:00 2001 From: pxadmin Date: Wed, 31 Oct 2018 15:21:15 +0200 Subject: [PATCH 04/28] Added cookie name extraction, valeus sent via risk_api --- .../DataContracts/Requests/Additional.cs | 3 +++ .../Internals/Helpers/PxConstants.cs | 1 + PerimeterXModule/Internals/PxContext.cs | 17 +++++++++++++++++ .../Internals/Validators/PXS2SValidator.cs | 3 ++- 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/PerimeterXModule/DataContracts/Requests/Additional.cs b/PerimeterXModule/DataContracts/Requests/Additional.cs index 99859a9..ae0ca58 100644 --- a/PerimeterXModule/DataContracts/Requests/Additional.cs +++ b/PerimeterXModule/DataContracts/Requests/Additional.cs @@ -44,5 +44,8 @@ public class Additional [DataMember(Name = "simulated_block")] public object SimulatedBlock; + [DataMember(Name = "risk_cookie_names")] + public string[] RiskCookieNames; + } } diff --git a/PerimeterXModule/Internals/Helpers/PxConstants.cs b/PerimeterXModule/Internals/Helpers/PxConstants.cs index da34f85..ce3a1fc 100644 --- a/PerimeterXModule/Internals/Helpers/PxConstants.cs +++ b/PerimeterXModule/Internals/Helpers/PxConstants.cs @@ -28,6 +28,7 @@ public static class PxConstants public static readonly string ENFORCER_TRUE_IP_HEADER = "x-px-enforcer-true-ip"; public static readonly string FIRST_PARTY_HEADER = "X-PX-FIRST-PARTY"; public static readonly string FIRST_PARTY_VALUE = "1"; + public static readonly string COOKIE_HEADER = "cookie"; // Endpoints public const string RISK_API_V2 = "/api/v2/risk"; diff --git a/PerimeterXModule/Internals/PxContext.cs b/PerimeterXModule/Internals/PxContext.cs index 4e8ed14..05d1812 100644 --- a/PerimeterXModule/Internals/PxContext.cs +++ b/PerimeterXModule/Internals/PxContext.cs @@ -43,6 +43,7 @@ public class PxContext public object DecodedOriginalToken { get; set; } public bool IsMobileRequest { get; set; } public string MobileHeader { get; set; } + public string[] CookieNames; public PxContext(HttpContext context, PxModuleConfigurationSection pxConfiguration) { @@ -57,6 +58,7 @@ public PxContext(HttpContext context, PxModuleConfigurationSection pxConfigurati // Get Headers // if userAgentOverride is present override the default user-agent + CookieNames = extractCookieNames(context.Request.Headers[PxConstants.COOKIE_HEADER]); string userAgentOverride = pxConfiguration.UserAgentOverride; if (!string.IsNullOrEmpty(userAgentOverride)) { @@ -162,6 +164,21 @@ public PxContext(HttpContext context, PxModuleConfigurationSection pxConfigurati SensitiveRoute = CheckSensitiveRoute(pxConfiguration.SensitiveRoutes, Uri); } + private string[] extractCookieNames(string cookieHeader) + { + string[] cookieNames = null; + if (cookieHeader != null) + { + var cookies = cookieHeader.Split(';'); + cookieNames = new string[cookies.Length]; + for (int i = 0; i < cookies.Length; i++) + { + cookieNames[i] = cookies[i].Split('=')[0].Trim(); + } + } + return cookieNames; + } + private bool CheckSensitiveRoute(StringCollection sensitiveRoutes, string uri) { if (sensitiveRoutes != null) diff --git a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs index 013a3c0..ae10e4b 100644 --- a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs +++ b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs @@ -91,7 +91,8 @@ public RiskResponse SendRiskResponse(PxContext PxContext) HttpVersion = PxContext.HttpVersion, RiskMode = riskMode, PxCookieHMAC = PxContext.PxCookieHmac, - CookieOrigin = PxContext.CookieOrigin + CookieOrigin = PxContext.CookieOrigin, + RiskCookieNames = PxContext.CookieNames }, FirstParty = PxConfig.FirstPartyEnabled From 8ca2b6a606d3e959ed57e557555c1484a06fb586 Mon Sep 17 00:00:00 2001 From: pxadmin Date: Thu, 1 Nov 2018 17:20:43 +0200 Subject: [PATCH 05/28] chanegd riskcookienames to requestcookienames --- PerimeterXModule/DataContracts/Requests/Additional.cs | 4 ++-- PerimeterXModule/Internals/Validators/PXS2SValidator.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PerimeterXModule/DataContracts/Requests/Additional.cs b/PerimeterXModule/DataContracts/Requests/Additional.cs index ae0ca58..4d7dec5 100644 --- a/PerimeterXModule/DataContracts/Requests/Additional.cs +++ b/PerimeterXModule/DataContracts/Requests/Additional.cs @@ -44,8 +44,8 @@ public class Additional [DataMember(Name = "simulated_block")] public object SimulatedBlock; - [DataMember(Name = "risk_cookie_names")] - public string[] RiskCookieNames; + [DataMember(Name = "request_cookie_names")] + public string[] RequestCookieNames; } } diff --git a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs index ae10e4b..00b1b3a 100644 --- a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs +++ b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs @@ -92,7 +92,7 @@ public RiskResponse SendRiskResponse(PxContext PxContext) RiskMode = riskMode, PxCookieHMAC = PxContext.PxCookieHmac, CookieOrigin = PxContext.CookieOrigin, - RiskCookieNames = PxContext.CookieNames + RequestCookieNames = PxContext.CookieNames }, FirstParty = PxConfig.FirstPartyEnabled From 90649c11f9fd3e9263ae47879f0b587e673cafa0 Mon Sep 17 00:00:00 2001 From: pxadmin Date: Thu, 8 Nov 2018 09:46:49 +0200 Subject: [PATCH 06/28] Added pxhd and vid to risk response. Added pxhd and pxvid to response set cookie --- .../DataContracts/Requests/RiskRequest.cs | 6 ++++++ .../DataContracts/Responses/RiskResponse.cs | 6 ++++++ .../Internals/Helpers/PxConstants.cs | 6 +++++- PerimeterXModule/Internals/PxContext.cs | 12 ++++++++++++ .../Internals/Validators/PXCookieValidator.cs | 1 + .../Internals/Validators/PXS2SValidator.cs | 15 +++++++++++++-- PerimeterXModule/PxModule.cs | 16 ++++++++++++++++ 7 files changed, 59 insertions(+), 3 deletions(-) diff --git a/PerimeterXModule/DataContracts/Requests/RiskRequest.cs b/PerimeterXModule/DataContracts/Requests/RiskRequest.cs index 3946a4c..570a0be 100644 --- a/PerimeterXModule/DataContracts/Requests/RiskRequest.cs +++ b/PerimeterXModule/DataContracts/Requests/RiskRequest.cs @@ -11,6 +11,12 @@ public class RiskRequest [DataMember(Name = "vid", EmitDefaultValue = false)] public string Vid; + [DataMember(Name = "pxhd", EmitDefaultValue = false)] + public string Pxhd; + + [DataMember(Name = "vid_source", EmitDefaultValue = false)] + public string VidSource; + [DataMember(Name = "uuid", EmitDefaultValue = false)] public string UUID; diff --git a/PerimeterXModule/DataContracts/Responses/RiskResponse.cs b/PerimeterXModule/DataContracts/Responses/RiskResponse.cs index 0cc7cb2..86465fd 100644 --- a/PerimeterXModule/DataContracts/Responses/RiskResponse.cs +++ b/PerimeterXModule/DataContracts/Responses/RiskResponse.cs @@ -14,6 +14,12 @@ public class RiskResponse [DataMember(Name = "uuid")] public string Uuid; + [DataMember(Name = "vid")] + public string Vid; + + [DataMember(Name = "pxhd")] + public string Pxhd; + [DataMember(Name = "score")] public int Score; diff --git a/PerimeterXModule/Internals/Helpers/PxConstants.cs b/PerimeterXModule/Internals/Helpers/PxConstants.cs index ce3a1fc..de367d2 100644 --- a/PerimeterXModule/Internals/Helpers/PxConstants.cs +++ b/PerimeterXModule/Internals/Helpers/PxConstants.cs @@ -10,10 +10,12 @@ namespace PerimeterX public static class PxConstants { public static readonly string HEX_ALPHABET = "0123456789abcdef"; - public static readonly string[] PX_COOKIES_PREFIX = { COOKIE_V1_PREFIX, COOKIE_V3_PREFIX }; + public static readonly string[] PX_COOKIES_PREFIX = { COOKIE_V1_PREFIX, COOKIE_V3_PREFIX, VID_COOKIE_PREFIX, PXHD_COOKIE_PREFIX }; public static readonly string[] PX_TOKEN_PREFIX = { TOKEN_V1_PREFIX, TOKEN_V3_PREFIX }; public const string COOKIE_V1_PREFIX = "_px"; public const string COOKIE_V3_PREFIX = "_px3"; + public const string VID_COOKIE_PREFIX = "_pxvid"; + public const string PXHD_COOKIE_PREFIX = "_pxhd"; public const string TOKEN_V1_PREFIX = "1"; public const string TOKEN_V3_PREFIX = "3"; public static readonly string PX_VALIDATED_HEADER = "X-PX-VALIDATED"; @@ -29,6 +31,8 @@ public static class PxConstants public static readonly string FIRST_PARTY_HEADER = "X-PX-FIRST-PARTY"; public static readonly string FIRST_PARTY_VALUE = "1"; public static readonly string COOKIE_HEADER = "cookie"; + public static readonly string VID_COOKIE = "VID_COOKIE"; + public static readonly string RISK_COOKIE = "RISK_COOKIE"; // Endpoints public const string RISK_API_V2 = "/api/v2/risk"; diff --git a/PerimeterXModule/Internals/PxContext.cs b/PerimeterXModule/Internals/PxContext.cs index 05d1812..dbef97d 100644 --- a/PerimeterXModule/Internals/PxContext.cs +++ b/PerimeterXModule/Internals/PxContext.cs @@ -44,6 +44,8 @@ public class PxContext public bool IsMobileRequest { get; set; } public string MobileHeader { get; set; } public string[] CookieNames; + public string VidSource { get; set; } + public string Pxhd { get; set; } public PxContext(HttpContext context, PxModuleConfigurationSection pxConfiguration) { @@ -144,6 +146,16 @@ public PxContext(HttpContext context, PxModuleConfigurationSection pxConfigurati PxCookies[key] = contextCookie.Get(key).Value; } } + if (PxCookies.ContainsKey("_pxvid")) + { + Vid = PxCookies["_pxvid"]; + VidSource = PxConstants.VID_COOKIE; + } + if (PxCookies.ContainsKey("_pxhd")) + { + Pxhd = PxCookies["_pxhd"]; + } + } diff --git a/PerimeterXModule/Internals/Validators/PXCookieValidator.cs b/PerimeterXModule/Internals/Validators/PXCookieValidator.cs index 71b77f2..b0a095e 100644 --- a/PerimeterXModule/Internals/Validators/PXCookieValidator.cs +++ b/PerimeterXModule/Internals/Validators/PXCookieValidator.cs @@ -71,6 +71,7 @@ public virtual bool Verify(PxContext context, IPxCookie pxCookie) context.Score = pxCookie.Score; context.UUID = pxCookie.Uuid; context.Vid = pxCookie.Vid; + context.VidSource = PxConstants.RISK_COOKIE; context.BlockAction = pxCookie.BlockAction; context.PxCookieHmac = pxCookie.Hmac; diff --git a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs index 00b1b3a..fbce18a 100644 --- a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs +++ b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs @@ -25,7 +25,14 @@ public bool VerifyS2S(PxContext PxContext) { RiskResponse riskResponse = SendRiskResponse(PxContext); PxContext.MadeS2SCallReason = true; - + if (riskResponse.Vid != null) + { + PxContext.Vid = riskResponse.Vid; + } + if (riskResponse.Pxhd != null) + { + PxContext.Pxhd = riskResponse.Pxhd; + } if (riskResponse.Score >= 0 && !string.IsNullOrEmpty(riskResponse.RiskResponseAction)) { int score = riskResponse.Score; @@ -81,7 +88,6 @@ public RiskResponse SendRiskResponse(PxContext PxContext) RiskRequest riskRequest = new RiskRequest { - Vid = PxContext.Vid, Request = Request.CreateRequestFromContext(PxContext), Additional = new Additional { @@ -103,6 +109,11 @@ public RiskResponse SendRiskResponse(PxContext PxContext) riskRequest.Vid = PxContext.Vid; } + if (!string.IsNullOrEmpty(PxContext.Pxhd)) + { + riskRequest.Pxhd = PxContext.Pxhd; + } + if (!string.IsNullOrEmpty(PxContext.UUID)) { riskRequest.UUID = PxContext.UUID; diff --git a/PerimeterXModule/PxModule.cs b/PerimeterXModule/PxModule.cs index 3b586a5..3e29504 100644 --- a/PerimeterXModule/PxModule.cs +++ b/PerimeterXModule/PxModule.cs @@ -355,6 +355,8 @@ public static void ResponseBlockPage(PxContext pxContext, PxModuleConfigurationS TemplateFactory.getTemplate(template, config, pxContext.UUID, pxContext.Vid, pxContext.IsMobileRequest, pxContext.BlockAction); pxContext.ApplicationContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + + if (pxContext.IsMobileRequest) { pxContext.ApplicationContext.Response.ContentType = "application/json"; @@ -376,6 +378,19 @@ public static void ResponseBlockPage(PxContext pxContext, PxModuleConfigurationS pxContext.ApplicationContext.Response.Write(content); } + private static void SetPxhdAndVid(PxContext pxContext) + { + + if (!string.IsNullOrEmpty(pxContext.Vid)) + { + pxContext.ApplicationContext.Response.AddHeader("Set-Cookie", "_pxvid=" + pxContext.Vid); + } + if (!string.IsNullOrEmpty(pxContext.Pxhd)) + { + pxContext.ApplicationContext.Response.AddHeader("Set-Cookie", "_pxhd=" + pxContext.Pxhd); + } + } + public void Dispose() { if (httpHandler != null) @@ -506,6 +521,7 @@ private void HandleVerification(HttpApplication application) PxLoggingUtils.LogDebug(string.Format("Invalid request to {0}", application.Context.Request.RawUrl)); PostBlockActivity(pxContext); } + SetPxhdAndVid(pxContext); // If implemented, run the customVerificationHandler. if (!string.IsNullOrEmpty(customVerificationHandler)) From 7f81875b8e53b0dbeb54ee63901400d53879bb8c Mon Sep 17 00:00:00 2001 From: pxadmin Date: Thu, 8 Nov 2018 10:06:56 +0200 Subject: [PATCH 07/28] changed vid and pxhd keys to constant types --- PerimeterXModule/Internals/PxContext.cs | 8 ++++---- PerimeterXModule/PxModule.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/PerimeterXModule/Internals/PxContext.cs b/PerimeterXModule/Internals/PxContext.cs index dbef97d..a78ee45 100644 --- a/PerimeterXModule/Internals/PxContext.cs +++ b/PerimeterXModule/Internals/PxContext.cs @@ -146,14 +146,14 @@ public PxContext(HttpContext context, PxModuleConfigurationSection pxConfigurati PxCookies[key] = contextCookie.Get(key).Value; } } - if (PxCookies.ContainsKey("_pxvid")) + if (PxCookies.ContainsKey(PxConstants.VID_COOKIE_PREFIX)) { - Vid = PxCookies["_pxvid"]; + Vid = PxCookies[PxConstants.VID_COOKIE_PREFIX]; VidSource = PxConstants.VID_COOKIE; } - if (PxCookies.ContainsKey("_pxhd")) + if (PxCookies.ContainsKey(PxConstants.PXHD_COOKIE_PREFIX)) { - Pxhd = PxCookies["_pxhd"]; + Pxhd = PxCookies[PxConstants.PXHD_COOKIE_PREFIX]; } } diff --git a/PerimeterXModule/PxModule.cs b/PerimeterXModule/PxModule.cs index 3e29504..5b3d6c9 100644 --- a/PerimeterXModule/PxModule.cs +++ b/PerimeterXModule/PxModule.cs @@ -383,11 +383,11 @@ private static void SetPxhdAndVid(PxContext pxContext) if (!string.IsNullOrEmpty(pxContext.Vid)) { - pxContext.ApplicationContext.Response.AddHeader("Set-Cookie", "_pxvid=" + pxContext.Vid); + pxContext.ApplicationContext.Response.AddHeader("Set-Cookie", PxConstants.VID_COOKIE_PREFIX + "=" + pxContext.Vid); } if (!string.IsNullOrEmpty(pxContext.Pxhd)) { - pxContext.ApplicationContext.Response.AddHeader("Set-Cookie", "_pxhd=" + pxContext.Pxhd); + pxContext.ApplicationContext.Response.AddHeader("Set-Cookie", PxConstants.PXHD_COOKIE_PREFIX + "=" + pxContext.Pxhd); } } From f68af5be4196569cfddd6574879a20c61501e684 Mon Sep 17 00:00:00 2001 From: pxadmin Date: Thu, 15 Nov 2018 13:12:20 +0200 Subject: [PATCH 08/28] Added pxhd to pagerequested activitiy rest call Added blockaction to block activity rest call Removed vid from set cookie response header --- PerimeterXModule/DataContracts/Activities/Activity.cs | 3 +++ .../DataContracts/Activities/ActivityDetails.cs | 5 ++++- PerimeterXModule/PxModule.cs | 11 ++++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/PerimeterXModule/DataContracts/Activities/Activity.cs b/PerimeterXModule/DataContracts/Activities/Activity.cs index 249d9d6..82cb25b 100644 --- a/PerimeterXModule/DataContracts/Activities/Activity.cs +++ b/PerimeterXModule/DataContracts/Activities/Activity.cs @@ -32,5 +32,8 @@ public class Activity [DataMember(Name = "http_method", EmitDefaultValue = false)] public string HttpMethod; + + [DataMember(Name = "pxhd", EmitDefaultValue = false)] + public string pxhd; } } diff --git a/PerimeterXModule/DataContracts/Activities/ActivityDetails.cs b/PerimeterXModule/DataContracts/Activities/ActivityDetails.cs index a994034..a1f4b06 100644 --- a/PerimeterXModule/DataContracts/Activities/ActivityDetails.cs +++ b/PerimeterXModule/DataContracts/Activities/ActivityDetails.cs @@ -31,7 +31,10 @@ public class ActivityDetails : IActivityDetails [DataMember(Name = "risk_rtt")] public long RiskRoundtripTime; - } + + [DataMember(Name = "block_action")] + public string BlockAction; + } [DataContract] public class EnforcerTelemetryActivityDetails : IActivityDetails diff --git a/PerimeterXModule/PxModule.cs b/PerimeterXModule/PxModule.cs index 5b3d6c9..5160e7c 100644 --- a/PerimeterXModule/PxModule.cs +++ b/PerimeterXModule/PxModule.cs @@ -251,7 +251,8 @@ private void PostBlockActivity(PxContext pxContext) BlockUuid = pxContext.UUID, ModuleVersion = PxConstants.MODULE_VERSION, RiskScore = pxContext.Score, - RiskRoundtripTime = pxContext.RiskRoundtripTime + RiskRoundtripTime = pxContext.RiskRoundtripTime, + BlockAction = pxContext.BlockAction }); } } @@ -313,6 +314,10 @@ private void PostActivity(PxContext pxContext, string eventType, ActivityDetails if (eventType.Equals("page_requested")) { activity.HttpMethod = "Post"; + if (!string.IsNullOrEmpty(pxContext.Pxhd)) + { + activity.pxhd = pxContext.Pxhd; + } } if (!string.IsNullOrEmpty(pxContext.Vid)) @@ -381,10 +386,6 @@ public static void ResponseBlockPage(PxContext pxContext, PxModuleConfigurationS private static void SetPxhdAndVid(PxContext pxContext) { - if (!string.IsNullOrEmpty(pxContext.Vid)) - { - pxContext.ApplicationContext.Response.AddHeader("Set-Cookie", PxConstants.VID_COOKIE_PREFIX + "=" + pxContext.Vid); - } if (!string.IsNullOrEmpty(pxContext.Pxhd)) { pxContext.ApplicationContext.Response.AddHeader("Set-Cookie", PxConstants.PXHD_COOKIE_PREFIX + "=" + pxContext.Pxhd); From aacf6a03613d40e4f663bdec0afcd3e7f8a38218 Mon Sep 17 00:00:00 2001 From: pxadmin Date: Thu, 15 Nov 2018 16:24:39 +0200 Subject: [PATCH 09/28] Added pxhd to block activity --- PerimeterXModule/PxModule.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/PerimeterXModule/PxModule.cs b/PerimeterXModule/PxModule.cs index 5160e7c..3f49d39 100644 --- a/PerimeterXModule/PxModule.cs +++ b/PerimeterXModule/PxModule.cs @@ -314,11 +314,12 @@ private void PostActivity(PxContext pxContext, string eventType, ActivityDetails if (eventType.Equals("page_requested")) { activity.HttpMethod = "Post"; - if (!string.IsNullOrEmpty(pxContext.Pxhd)) - { - activity.pxhd = pxContext.Pxhd; - } } + if ((eventType.Equals("page_requested") || eventType.Equals("block")) && (!string.IsNullOrEmpty(pxContext.Pxhd))) + { + activity.pxhd = pxContext.Pxhd; + } + if (!string.IsNullOrEmpty(pxContext.Vid)) { From 1dbb63377487b22a193af89614affb9ae9a1850d Mon Sep 17 00:00:00 2001 From: Johnny Tordgeman Date: Wed, 21 Nov 2018 22:12:07 +0200 Subject: [PATCH 10/28] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0696c87..a50bfb9 100644 --- a/README.md +++ b/README.md @@ -128,8 +128,8 @@ On both cases if the URL is not a valid format an exception will be thrown Example below: ```xml ... - jsRef="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" - cssRef="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" + jsRef="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" + cssRef="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" ... ``` #### Changing the Minimum Score for Blocking From eb7c742d1bed9020c1c90077b2c31d00ca539022 Mon Sep 17 00:00:00 2001 From: pxadmin Date: Tue, 27 Nov 2018 22:29:41 +0200 Subject: [PATCH 11/28] [ADD] support for data enrichment on context. --- .../DataContracts/Responses/RiskResponse.cs | 3 +++ .../Internals/Cookies/DataEnrichmentCookie.cs | 19 ++++++++++++++ .../Internals/Cookies/PxCookieUtils.cs | 25 ++++++++++++++++++- .../Internals/Helpers/PxConstants.cs | 5 ++-- PerimeterXModule/Internals/PxContext.cs | 6 +++-- .../Internals/Validators/PXS2SValidator.cs | 15 ++++++++--- PerimeterXModule/PerimeterXModule.csproj | 1 + 7 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 PerimeterXModule/Internals/Cookies/DataEnrichmentCookie.cs diff --git a/PerimeterXModule/DataContracts/Responses/RiskResponse.cs b/PerimeterXModule/DataContracts/Responses/RiskResponse.cs index 0cc7cb2..5836175 100644 --- a/PerimeterXModule/DataContracts/Responses/RiskResponse.cs +++ b/PerimeterXModule/DataContracts/Responses/RiskResponse.cs @@ -25,6 +25,9 @@ public class RiskResponse [DataMember(Name = "error_msg")] public string ErrorMessage; + + [DataMember(Name = "data_enrichment")] + public object DataEnrichment; } diff --git a/PerimeterXModule/Internals/Cookies/DataEnrichmentCookie.cs b/PerimeterXModule/Internals/Cookies/DataEnrichmentCookie.cs new file mode 100644 index 0000000..ae324c8 --- /dev/null +++ b/PerimeterXModule/Internals/Cookies/DataEnrichmentCookie.cs @@ -0,0 +1,19 @@ +using System.Text; + +namespace PerimeterX.DataContracts.Cookies +{ + public sealed class DataEnrichmentCookie + { + private bool isValid = false; + private dynamic jsonPayload; + + public bool IsValid { set { isValid = value; } get { return isValid; } } + public dynamic JsonPayload { set { jsonPayload = value; } get { return jsonPayload; } } + + public DataEnrichmentCookie(dynamic jsonPayload, bool isValid) + { + this.jsonPayload = jsonPayload; + this.isValid = isValid; + } + } +} diff --git a/PerimeterXModule/Internals/Cookies/PxCookieUtils.cs b/PerimeterXModule/Internals/Cookies/PxCookieUtils.cs index 6aeeff5..1bf2531 100644 --- a/PerimeterXModule/Internals/Cookies/PxCookieUtils.cs +++ b/PerimeterXModule/Internals/Cookies/PxCookieUtils.cs @@ -62,6 +62,29 @@ public static string ByteArrayToHexString(byte[] input) } return sb.ToString(); } - } + public static DataEnrichmentCookie GetDataEnrichmentCookie(Dictionary PxCookies, string cookieKey) + { + DataEnrichmentCookie dataEnrichment = new DataEnrichmentCookie(JSON.DeserializeDynamic("{}"), false); + if (PxCookies.ContainsKey(PxConstants.COOKIE_DATA_ENRICHMENT_PREFIX)) + { + string rawCookie = PxCookies[PxConstants.COOKIE_DATA_ENRICHMENT_PREFIX]; + string[] splitRawCookie = rawCookie.Split(new char[] { ':' }, 2); + if (splitRawCookie.Length != 2) + { + return dataEnrichment; + } + + string hmac = splitRawCookie[0]; + string encodedPayload = splitRawCookie[1]; + bool isValid = IsHMACValid(cookieKey, encodedPayload, hmac); + dataEnrichment.IsValid = isValid; + byte[] bytes = Convert.FromBase64String(encodedPayload); + string decodedPayload = Encoding.UTF8.GetString(bytes); + dataEnrichment.JsonPayload = JSON.DeserializeDynamic(decodedPayload); + } + + return dataEnrichment; + } + } } diff --git a/PerimeterXModule/Internals/Helpers/PxConstants.cs b/PerimeterXModule/Internals/Helpers/PxConstants.cs index ce3a1fc..2bc7c01 100644 --- a/PerimeterXModule/Internals/Helpers/PxConstants.cs +++ b/PerimeterXModule/Internals/Helpers/PxConstants.cs @@ -10,10 +10,11 @@ namespace PerimeterX public static class PxConstants { public static readonly string HEX_ALPHABET = "0123456789abcdef"; - public static readonly string[] PX_COOKIES_PREFIX = { COOKIE_V1_PREFIX, COOKIE_V3_PREFIX }; + public static readonly string[] PX_COOKIES_PREFIX = { COOKIE_V1_PREFIX, COOKIE_V3_PREFIX, COOKIE_DATA_ENRICHMENT_PREFIX }; public static readonly string[] PX_TOKEN_PREFIX = { TOKEN_V1_PREFIX, TOKEN_V3_PREFIX }; public const string COOKIE_V1_PREFIX = "_px"; public const string COOKIE_V3_PREFIX = "_px3"; + public const string COOKIE_DATA_ENRICHMENT_PREFIX = "_pxde"; public const string TOKEN_V1_PREFIX = "1"; public const string TOKEN_V3_PREFIX = "3"; public static readonly string PX_VALIDATED_HEADER = "X-PX-VALIDATED"; @@ -31,7 +32,7 @@ public static class PxConstants public static readonly string COOKIE_HEADER = "cookie"; // Endpoints - public const string RISK_API_V2 = "/api/v2/risk"; + public const string RISK_API_PATH = "/api/v3/risk"; public const string ACTIVITIES_API_PATH = "/api/v1/collector/s2s"; public const string ENFORCER_TELEMETRY_API_PATH = "/api/v2/risk/telemetry"; diff --git a/PerimeterXModule/Internals/PxContext.cs b/PerimeterXModule/Internals/PxContext.cs index 05d1812..1905d14 100644 --- a/PerimeterXModule/Internals/PxContext.cs +++ b/PerimeterXModule/Internals/PxContext.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Web; using System; -using System.Net; using System.Collections.Specialized; using System.Linq; +using PerimeterX.DataContracts.Cookies; namespace PerimeterX { @@ -44,6 +44,7 @@ public class PxContext public bool IsMobileRequest { get; set; } public string MobileHeader { get; set; } public string[] CookieNames; + public DataEnrichmentCookie DataEnrichment { get; set; } public PxContext(HttpContext context, PxModuleConfigurationSection pxConfiguration) { @@ -144,8 +145,9 @@ public PxContext(HttpContext context, PxModuleConfigurationSection pxConfigurati PxCookies[key] = contextCookie.Get(key).Value; } } - } + DataEnrichment = PxCookieUtils.GetDataEnrichmentCookie(PxCookies, pxConfiguration.CookieKey); + } Hostname = context.Request.Url.Host; diff --git a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs index 00b1b3a..f88fd9e 100644 --- a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs +++ b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs @@ -2,6 +2,7 @@ using System; using System.Diagnostics; using System.Threading.Tasks; +using PerimeterX.DataContracts.Cookies; namespace PerimeterX { @@ -25,7 +26,6 @@ public bool VerifyS2S(PxContext PxContext) { RiskResponse riskResponse = SendRiskResponse(PxContext); PxContext.MadeS2SCallReason = true; - if (riskResponse.Score >= 0 && !string.IsNullOrEmpty(riskResponse.RiskResponseAction)) { int score = riskResponse.Score; @@ -54,6 +54,15 @@ public bool VerifyS2S(PxContext PxContext) PxContext.S2SHttpErrorMessage = riskResponse.ErrorMessage; retVal = false; } + + DataEnrichmentCookie dataEnrichment = new DataEnrichmentCookie(JSON.DeserializeDynamic("{}"), true); + if (riskResponse.DataEnrichment != null) + { + string dataEnrichmentString = riskResponse.DataEnrichment.ToString(); + var dataEnrichmentPayload = JSON.DeserializeDynamic(dataEnrichmentString); + dataEnrichment = new DataEnrichmentCookie(dataEnrichmentPayload, true); + } + PxContext.DataEnrichment = dataEnrichment; } catch (Exception ex) { @@ -72,7 +81,6 @@ public bool VerifyS2S(PxContext PxContext) public RiskResponse SendRiskResponse(PxContext PxContext) { - var riskMode = ModuleMode.BLOCK_MODE; if (PxConfig.MonitorMode == true) { @@ -134,9 +142,8 @@ public RiskResponse SendRiskResponse(PxContext PxContext) riskRequest.Additional.SimulatedBlock = PxConfig.MonitorMode; - string requestJson = JSON.SerializeDynamic(riskRequest, PxConstants.JSON_OPTIONS); - var responseJson = httpHandler.Post(requestJson, PxConstants.RISK_API_V2); + var responseJson = httpHandler.Post(requestJson, PxConstants.RISK_API_PATH); return JSON.Deserialize(responseJson, PxConstants.JSON_OPTIONS); } } diff --git a/PerimeterXModule/PerimeterXModule.csproj b/PerimeterXModule/PerimeterXModule.csproj index 9f13d2d..0682d02 100644 --- a/PerimeterXModule/PerimeterXModule.csproj +++ b/PerimeterXModule/PerimeterXModule.csproj @@ -68,6 +68,7 @@ + From 9ac9bf65be3ee0e415f4c61d4686455400d8c21d Mon Sep 17 00:00:00 2001 From: SaraLumelsky <37770740+SaraLumelsky@users.noreply.github.com> Date: Sun, 2 Dec 2018 11:01:18 +0200 Subject: [PATCH 12/28] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index a50bfb9..dda2444 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Table of Contents * [Dependencies](#dependencies) * [Installation](#installation) * [Basic Usage Example](#basic-usage) + * [Upgrading](#upgrade) **[Configuration](#configuration)** * [Customizing Default Block Pages](#custom-block-page) @@ -93,6 +94,9 @@ Add site specific configuration (configuration level) ``` +## Upgrading + +TBD ### Configuration Options From c61f0dc01c70952e194068c0fa7f6200547b3685 Mon Sep 17 00:00:00 2001 From: Ilai Fallach Date: Mon, 24 Dec 2018 01:03:12 +0200 Subject: [PATCH 13/28] [CHANGED] DataEnrichment on context to Pxde and IsPxdeVerified --- CHANGELOG.md | 108 ++++++------- .../Internals/Cookies/PxCookieUtils.cs | 149 +++++++++--------- PerimeterXModule/Internals/PxContext.cs | 7 +- .../Internals/Validators/PXS2SValidator.cs | 3 +- README.md | 34 +++- 5 files changed, 169 insertions(+), 132 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a65397e..63be7f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,89 +3,91 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) -##[2.7.0] - 2018-09-16 +## [2.8.0] - 2018-12-25 ### Added - - Support for simulated_block +- Added data enrichment to context + +## [2.7.0] - 2018-09-16 +### Added +- Support for simulated_block ### Fixed - - Captcha v2 template and error handling - - Various stablity and performance fixes +- Captcha v2 template and error handling +- Various stablity and performance fixes -##[2.6.0] - 2018-08-07 +## [2.6.0] - 2018-08-07 ### Added - - Support for captcha v2 +- Support for captcha v2 -##[2.5.1] - 2018-11-06 +## [2.5.1] - 2018-11-06 ### Fixed - - Mobile token extraction in cookie validator +- Mobile token extraction in cookie validator -##[2.5.0] - 2018-14-03 +## [2.5.0] - 2018-14-03 ### Added - - Support for first party +- Support for first party -##[2.4.0] - 2018-21-02 +## [2.4.0] - 2018-21-02 ### Added - - Support enforced specific routes +- Support enforced specific routes -##[2.3.0] - 2018-05-02 +## [2.3.0] - 2018-05-02 ### Added - - Support for mobile sdk - - Support for original tokens - - Support funCaptcha in mobile - - Enforcer Telemetry +- Support for mobile sdk +- Support for original tokens +- Support funCaptcha in mobile +- Enforcer Telemetry ### Modified - - Edit block page footer - - Edit reCaptcha template to use b64 captcha - - Enrichment for async activities +- Edit block page footer +- Edit reCaptcha template to use b64 captcha +- Enrichment for async activities ### Fixed - - Handling duplicate cookies +- Handling duplicate cookies -##[2.2.0] - 2017-11-10 +## [2.2.0] - 2017-11-10 ### Fixed - - Fixed default value for sensitive_route - - Using action_block to render block pages - - Naming for s2s expired_cookie reason to cookie_expired +- Fixed default value for sensitive_route +- Using action_block to render block pages +- Naming for s2s expired_cookie reason to cookie_expired ### Added - - JS Challenge support - - FunCaptcha support - - CustomVerificationHandler support - - MonitorMode and set default to true - Please note: MonitorMode is breaking backward support - if you upgrade to this version or further - and want to keep your blocking active, please set its value to False +- JS Challenge support +- FunCaptcha support +- CustomVerificationHandler support +- MonitorMode and set default to true + Please note: MonitorMode is breaking backward support + if you upgrade to this version or further + and want to keep your blocking active, please set its value to False -##[2.1.0] - 2017-04-06 +## [2.1.0] - 2017-04-06 ### Fixed - - Renamed risk_score to block_score in activity details - - Fixed block score threshold +- Renamed risk_score to block_score in activity details +- Fixed block score threshold ## Added - - Support for sensitive routes - - Log page requested reason - - Mesure risk rout trip time +- Support for sensitive routes +- Log page requested reason +- Mesure risk rout trip time - -##[2.0.3] - 2017-15-05 +## [2.0.3] - 2017-15-05 ### Fixed - - Collect right Hostname in context - - Renamed module_version +- Collect right Hostname in context +- Renamed module_version ### Added - - Block/Page Requested Activities now sends module_verison and risk_socre - - Support Cookie v3 - - Support RiskAPI v2 +- Block/Page Requested Activities now sends module_verison and risk_socre +- Support Cookie v3 +- Support RiskAPI v2 ### Changed - - Moved PxModule verification code, request state, api calls to managable files - - New classes, Validators, DataContracts (Cookies, Activities, Requests etc...) - - Refactor module to work with PxContext - - Reordered library into folders - +- Moved PxModule verification code, request state, api calls to managable files +- New classes, Validators, DataContracts (Cookies, Activities, Requests etc...) +- Refactor module to work with PxContext +- Reordered library into folders -##[1.2.0] - 2017-24-04 +## [1.2.0] - 2017-24-04 - Support custom header for user-agent -##[1.1.1] - 2017-20-04 +## [1.1.1] - 2017-20-04 - added .axd files to whitelist files - sending px_orig_value when decryption fails -##[1.1] - 2017-28-03 +## [1.1] - 2017-28-03 - Moved server url to new URL - New design for block pages - Block page customisation diff --git a/PerimeterXModule/Internals/Cookies/PxCookieUtils.cs b/PerimeterXModule/Internals/Cookies/PxCookieUtils.cs index 1bf2531..2393b9e 100644 --- a/PerimeterXModule/Internals/Cookies/PxCookieUtils.cs +++ b/PerimeterXModule/Internals/Cookies/PxCookieUtils.cs @@ -7,84 +7,91 @@ namespace PerimeterX { - public static class PxCookieUtils - { - public static IPxCookie BuildCookie(PxModuleConfigurationSection config, Dictionary cookies, ICookieDecoder cookieDecoder) - { - if (cookies.Count == 0) - { - return null; - } + public static class PxCookieUtils + { + public static IPxCookie BuildCookie(PxModuleConfigurationSection config, Dictionary cookies, ICookieDecoder cookieDecoder) + { + if (cookies.Count == 0) + { + return null; + } - if (cookies.ContainsKey(PxConstants.COOKIE_V1_PREFIX)) - { - return new PxCookieV1(cookieDecoder, cookies[PxConstants.COOKIE_V1_PREFIX]); - } + if (cookies.ContainsKey(PxConstants.COOKIE_V1_PREFIX)) + { + return new PxCookieV1(cookieDecoder, cookies[PxConstants.COOKIE_V1_PREFIX]); + } - return new PxCookieV3(cookieDecoder, cookies[PxConstants.COOKIE_V3_PREFIX]); - } + return new PxCookieV3(cookieDecoder, cookies[PxConstants.COOKIE_V3_PREFIX]); + } - public static T Deserialize(ICookieDecoder cookieDecoder, string rawCookie) - { - string cookieString = cookieDecoder.Decode(rawCookie); - if (string.IsNullOrEmpty(cookieString)) - { - return default(T); - } + public static T Deserialize(ICookieDecoder cookieDecoder, string rawCookie) + { + string cookieString = cookieDecoder.Decode(rawCookie); + if (string.IsNullOrEmpty(cookieString)) + { + return default(T); + } - return JSON.Deserialize(cookieString, PxConstants.JSON_OPTIONS); - } + return JSON.Deserialize(cookieString, PxConstants.JSON_OPTIONS); + } - public static bool IsExpired(double date) - { - double now = DateTime.UtcNow - .Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)) - .TotalMilliseconds; - return date < now; - } + public static bool IsExpired(double date) + { + double now = DateTime.UtcNow + .Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)) + .TotalMilliseconds; + return date < now; + } - public static bool IsHMACValid(string cookieKey, string UncodedHmac, string CookieHmac) - { - var cookieKeyBytes = Encoding.UTF8.GetBytes(cookieKey); - var hash = new HMACSHA256(cookieKeyBytes); - var expectedHashBytes = hash.ComputeHash(Encoding.UTF8.GetBytes(UncodedHmac)); - var encodedHmac = ByteArrayToHexString(expectedHashBytes); - return encodedHmac == CookieHmac; - } + public static bool IsHMACValid(string cookieKey, string UncodedHmac, string CookieHmac) + { + var cookieKeyBytes = Encoding.UTF8.GetBytes(cookieKey); + var hash = new HMACSHA256(cookieKeyBytes); + var expectedHashBytes = hash.ComputeHash(Encoding.UTF8.GetBytes(UncodedHmac)); + var encodedHmac = ByteArrayToHexString(expectedHashBytes); + return encodedHmac == CookieHmac; + } - public static string ByteArrayToHexString(byte[] input) - { - StringBuilder sb = new StringBuilder(input.Length * 2); - foreach (byte b in input) - { - sb.Append(PxConstants.HEX_ALPHABET[b >> 4]); - sb.Append(PxConstants.HEX_ALPHABET[b & 0xF]); - } - return sb.ToString(); - } + public static string ByteArrayToHexString(byte[] input) + { + StringBuilder sb = new StringBuilder(input.Length * 2); + foreach (byte b in input) + { + sb.Append(PxConstants.HEX_ALPHABET[b >> 4]); + sb.Append(PxConstants.HEX_ALPHABET[b & 0xF]); + } + return sb.ToString(); + } - public static DataEnrichmentCookie GetDataEnrichmentCookie(Dictionary PxCookies, string cookieKey) - { - DataEnrichmentCookie dataEnrichment = new DataEnrichmentCookie(JSON.DeserializeDynamic("{}"), false); - if (PxCookies.ContainsKey(PxConstants.COOKIE_DATA_ENRICHMENT_PREFIX)) - { - string rawCookie = PxCookies[PxConstants.COOKIE_DATA_ENRICHMENT_PREFIX]; - string[] splitRawCookie = rawCookie.Split(new char[] { ':' }, 2); - if (splitRawCookie.Length != 2) - { - return dataEnrichment; - } + public static DataEnrichmentCookie GetDataEnrichmentCookie(Dictionary PxCookies, string cookieKey) + { + DataEnrichmentCookie dataEnrichment = new DataEnrichmentCookie(JSON.DeserializeDynamic("{}"), false); + if (PxCookies.ContainsKey(PxConstants.COOKIE_DATA_ENRICHMENT_PREFIX)) + { + string rawCookie = PxCookies[PxConstants.COOKIE_DATA_ENRICHMENT_PREFIX]; + string[] splitRawCookie = rawCookie.Split(new char[] { ':' }, 2); + if (splitRawCookie.Length != 2) + { + return dataEnrichment; + } - string hmac = splitRawCookie[0]; - string encodedPayload = splitRawCookie[1]; - bool isValid = IsHMACValid(cookieKey, encodedPayload, hmac); - dataEnrichment.IsValid = isValid; - byte[] bytes = Convert.FromBase64String(encodedPayload); - string decodedPayload = Encoding.UTF8.GetString(bytes); - dataEnrichment.JsonPayload = JSON.DeserializeDynamic(decodedPayload); - } - - return dataEnrichment; - } - } + string hmac = splitRawCookie[0]; + string encodedPayload = splitRawCookie[1]; + bool isValid = IsHMACValid(cookieKey, encodedPayload, hmac); + dataEnrichment.IsValid = isValid; + byte[] bytes = Convert.FromBase64String(encodedPayload); + string decodedPayload = Encoding.UTF8.GetString(bytes); + try + { + dataEnrichment.JsonPayload = JSON.DeserializeDynamic(decodedPayload); + } + catch (Exception err) + { + PxLoggingUtils.LogDebug(string.Format("Failed deserializing pxde into json")); + } + } + + return dataEnrichment; + } + } } diff --git a/PerimeterXModule/Internals/PxContext.cs b/PerimeterXModule/Internals/PxContext.cs index 1905d14..7575ca7 100644 --- a/PerimeterXModule/Internals/PxContext.cs +++ b/PerimeterXModule/Internals/PxContext.cs @@ -44,7 +44,8 @@ public class PxContext public bool IsMobileRequest { get; set; } public string MobileHeader { get; set; } public string[] CookieNames; - public DataEnrichmentCookie DataEnrichment { get; set; } + private bool IsPxdeVerified { get; set; } + private dynamic Pxde { get; set; } public PxContext(HttpContext context, PxModuleConfigurationSection pxConfiguration) { @@ -146,7 +147,9 @@ public PxContext(HttpContext context, PxModuleConfigurationSection pxConfigurati } } - DataEnrichment = PxCookieUtils.GetDataEnrichmentCookie(PxCookies, pxConfiguration.CookieKey); + DataEnrichmentCookie deCookie = PxCookieUtils.GetDataEnrichmentCookie(PxCookies, pxConfiguration.CookieKey); + IsPxdeVerified = deCookie.IsValid; + Pxde = deCookie.JsonPayload; } Hostname = context.Request.Url.Host; diff --git a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs index f88fd9e..8ef3c8e 100644 --- a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs +++ b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs @@ -62,7 +62,8 @@ public bool VerifyS2S(PxContext PxContext) var dataEnrichmentPayload = JSON.DeserializeDynamic(dataEnrichmentString); dataEnrichment = new DataEnrichmentCookie(dataEnrichmentPayload, true); } - PxContext.DataEnrichment = dataEnrichment; + PxContext.IsPxdeVerified = dataEnrichment.IsValid; + PxContext.Pxde = dataEnrichment.JsonPayload; } catch (Exception ex) { diff --git a/README.md b/README.md index a50bfb9..e9a30f3 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,6 @@ Table of Contents * [Enable/Disable Captcha](#captcha-support) * [First Party Mode](#first-party) * [Extracting Real IP Address](#real-ip) - * [Override UA header](#override-ua) * [Filter Sensitive Headers](#sensitive-headers) * [Sensitive Routes](#sensitive-routes) * [Whitelist Routes](#whitelist-routes) @@ -31,6 +30,7 @@ Table of Contents * [Send Page Activities](#send-page-activities) * [Monitor Mode](#monitor-mode) * [Base URI](#base-uri) + * [Override UA header](#override-ua) **[Contributing](#contributing)** * [Tests](#tests) @@ -351,22 +351,46 @@ The user's user agent can be returned to the PerimeterX module using a name of a ... ``` +#### Data Enrichment + +Users can use the additional activity handler to retrieve information for the request using the data-enrichment object. First, check that the data enrichment object is verified, then you can access it's properties. + +```c# +... + +namespace MyApp +{ + public class MyVerificationHandler : IVerificationHandler + { + public void Handle(HttpApplication application, PxContext pxContext, PxModuleConfigurationSection pxConfig) + { + ... + if (pxContext.IsPxdeVerified) { + dynamic pxde = pxContext.Pxde; + // do something with the data enrichment + } + ... + } + } +} +``` + Contributing ---------------------------------------- The following steps are welcome when contributing to our project. -###Fork/Clone +### Fork/Clone First and foremost, [Create a fork](https://guides.github.com/activities/forking/) of the repository, and clone it locally. Create a branch on your fork, preferably using a self descriptive branch name. -###Code/Run +### Code/Run Code your way out of your mess, and help improve our project by implementing missing features, adding capabilities or fixing bugs. To run the code, simply follow the steps in the [installation guide](#installation). Grab the keys from the PerimeterX Portal, and try refreshing your page several times continuously. If no default behaviours have been overridden, you should see the PerimeterX block page. Solve the CAPTCHA to clean yourself and start fresh again. -###Pull Request +### Pull Request After you have completed the process, create a pull request to the Upstream repository. Please provide a complete and thorough description explaining the changes. Remember this code has to be read by our maintainers, so keep it simple, smart and accurate. -###Thanks +### Thanks After all, you are helping us by contributing to this project, and we want to thank you for it. We highly appreciate your time invested in contributing to our project, and are glad to have people like you - kind helpers. From 98e8b09748f626129ef5bc38bdd8526b8270ebc2 Mon Sep 17 00:00:00 2001 From: pxadmin Date: Tue, 25 Dec 2018 17:35:42 +0200 Subject: [PATCH 14/28] [FIX] make de public in context. --- PerimeterXModule/Internals/PxContext.cs | 4 ++-- PerimeterXModule/Internals/Validators/PXS2SValidator.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/PerimeterXModule/Internals/PxContext.cs b/PerimeterXModule/Internals/PxContext.cs index 7575ca7..7649f0c 100644 --- a/PerimeterXModule/Internals/PxContext.cs +++ b/PerimeterXModule/Internals/PxContext.cs @@ -44,8 +44,8 @@ public class PxContext public bool IsMobileRequest { get; set; } public string MobileHeader { get; set; } public string[] CookieNames; - private bool IsPxdeVerified { get; set; } - private dynamic Pxde { get; set; } + public bool IsPxdeVerified { get; set; } + public dynamic Pxde { get; set; } public PxContext(HttpContext context, PxModuleConfigurationSection pxConfiguration) { diff --git a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs index 8ef3c8e..a0b598f 100644 --- a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs +++ b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs @@ -55,15 +55,15 @@ public bool VerifyS2S(PxContext PxContext) retVal = false; } - DataEnrichmentCookie dataEnrichment = new DataEnrichmentCookie(JSON.DeserializeDynamic("{}"), true); + DataEnrichmentCookie deCookie = new DataEnrichmentCookie(JSON.DeserializeDynamic("{}"), true); if (riskResponse.DataEnrichment != null) { string dataEnrichmentString = riskResponse.DataEnrichment.ToString(); var dataEnrichmentPayload = JSON.DeserializeDynamic(dataEnrichmentString); - dataEnrichment = new DataEnrichmentCookie(dataEnrichmentPayload, true); + deCookie = new DataEnrichmentCookie(dataEnrichmentPayload, true); } - PxContext.IsPxdeVerified = dataEnrichment.IsValid; - PxContext.Pxde = dataEnrichment.JsonPayload; + PxContext.IsPxdeVerified = deCookie.IsValid; + PxContext.Pxde = deCookie.JsonPayload; } catch (Exception ex) { From 9e74ba045738e863b29874a2b3d60282ad30493f Mon Sep 17 00:00:00 2001 From: SaraLumelsky <37770740+SaraLumelsky@users.noreply.github.com> Date: Wed, 26 Dec 2018 11:50:01 +0200 Subject: [PATCH 15/28] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dda2444..1f2cf83 100644 --- a/README.md +++ b/README.md @@ -94,9 +94,9 @@ Add site specific configuration (configuration level) ``` -## Upgrading +### Upgrading -TBD +Contact [PerimeterX Support](support@perimeterx.com) for details. ### Configuration Options From 6275cfa866556a8f49d9ba49858ecd8009274ce7 Mon Sep 17 00:00:00 2001 From: pxadmin Date: Thu, 3 Jan 2019 11:03:27 +0200 Subject: [PATCH 16/28] reverted --- .../DataContracts/Activities/Activity.cs | 3 --- .../Activities/ActivityDetails.cs | 5 +---- .../DataContracts/Requests/RiskRequest.cs | 6 ------ .../DataContracts/Responses/RiskResponse.cs | 6 ------ .../Internals/Helpers/PxConstants.cs | 8 ++------ PerimeterXModule/Internals/PxContext.cs | 14 ++----------- .../Internals/Validators/PXCookieValidator.cs | 1 - .../Internals/Validators/PXS2SValidator.cs | 15 +------------- PerimeterXModule/PxModule.cs | 20 +------------------ 9 files changed, 7 insertions(+), 71 deletions(-) diff --git a/PerimeterXModule/DataContracts/Activities/Activity.cs b/PerimeterXModule/DataContracts/Activities/Activity.cs index 82cb25b..249d9d6 100644 --- a/PerimeterXModule/DataContracts/Activities/Activity.cs +++ b/PerimeterXModule/DataContracts/Activities/Activity.cs @@ -32,8 +32,5 @@ public class Activity [DataMember(Name = "http_method", EmitDefaultValue = false)] public string HttpMethod; - - [DataMember(Name = "pxhd", EmitDefaultValue = false)] - public string pxhd; } } diff --git a/PerimeterXModule/DataContracts/Activities/ActivityDetails.cs b/PerimeterXModule/DataContracts/Activities/ActivityDetails.cs index a1f4b06..a994034 100644 --- a/PerimeterXModule/DataContracts/Activities/ActivityDetails.cs +++ b/PerimeterXModule/DataContracts/Activities/ActivityDetails.cs @@ -31,10 +31,7 @@ public class ActivityDetails : IActivityDetails [DataMember(Name = "risk_rtt")] public long RiskRoundtripTime; - - [DataMember(Name = "block_action")] - public string BlockAction; - } + } [DataContract] public class EnforcerTelemetryActivityDetails : IActivityDetails diff --git a/PerimeterXModule/DataContracts/Requests/RiskRequest.cs b/PerimeterXModule/DataContracts/Requests/RiskRequest.cs index 570a0be..3946a4c 100644 --- a/PerimeterXModule/DataContracts/Requests/RiskRequest.cs +++ b/PerimeterXModule/DataContracts/Requests/RiskRequest.cs @@ -11,12 +11,6 @@ public class RiskRequest [DataMember(Name = "vid", EmitDefaultValue = false)] public string Vid; - [DataMember(Name = "pxhd", EmitDefaultValue = false)] - public string Pxhd; - - [DataMember(Name = "vid_source", EmitDefaultValue = false)] - public string VidSource; - [DataMember(Name = "uuid", EmitDefaultValue = false)] public string UUID; diff --git a/PerimeterXModule/DataContracts/Responses/RiskResponse.cs b/PerimeterXModule/DataContracts/Responses/RiskResponse.cs index fe6462c..5836175 100644 --- a/PerimeterXModule/DataContracts/Responses/RiskResponse.cs +++ b/PerimeterXModule/DataContracts/Responses/RiskResponse.cs @@ -14,12 +14,6 @@ public class RiskResponse [DataMember(Name = "uuid")] public string Uuid; - [DataMember(Name = "vid")] - public string Vid; - - [DataMember(Name = "pxhd")] - public string Pxhd; - [DataMember(Name = "score")] public int Score; diff --git a/PerimeterXModule/Internals/Helpers/PxConstants.cs b/PerimeterXModule/Internals/Helpers/PxConstants.cs index cd2eca6..2bc7c01 100644 --- a/PerimeterXModule/Internals/Helpers/PxConstants.cs +++ b/PerimeterXModule/Internals/Helpers/PxConstants.cs @@ -10,13 +10,11 @@ namespace PerimeterX public static class PxConstants { public static readonly string HEX_ALPHABET = "0123456789abcdef"; - public static readonly string[] PX_COOKIES_PREFIX = { COOKIE_V1_PREFIX, COOKIE_V3_PREFIX, VID_COOKIE_PREFIX, PXHD_COOKIE_PREFIX, COOKIE_DATA_ENRICHMENT_PREFIX }; + public static readonly string[] PX_COOKIES_PREFIX = { COOKIE_V1_PREFIX, COOKIE_V3_PREFIX, COOKIE_DATA_ENRICHMENT_PREFIX }; public static readonly string[] PX_TOKEN_PREFIX = { TOKEN_V1_PREFIX, TOKEN_V3_PREFIX }; public const string COOKIE_V1_PREFIX = "_px"; public const string COOKIE_V3_PREFIX = "_px3"; - public const string VID_COOKIE_PREFIX = "_pxvid"; - public const string PXHD_COOKIE_PREFIX = "_pxhd"; - public const string COOKIE_DATA_ENRICHMENT_PREFIX = "_pxde"; + public const string COOKIE_DATA_ENRICHMENT_PREFIX = "_pxde"; public const string TOKEN_V1_PREFIX = "1"; public const string TOKEN_V3_PREFIX = "3"; public static readonly string PX_VALIDATED_HEADER = "X-PX-VALIDATED"; @@ -32,8 +30,6 @@ public static class PxConstants public static readonly string FIRST_PARTY_HEADER = "X-PX-FIRST-PARTY"; public static readonly string FIRST_PARTY_VALUE = "1"; public static readonly string COOKIE_HEADER = "cookie"; - public static readonly string VID_COOKIE = "VID_COOKIE"; - public static readonly string RISK_COOKIE = "RISK_COOKIE"; // Endpoints public const string RISK_API_PATH = "/api/v3/risk"; diff --git a/PerimeterXModule/Internals/PxContext.cs b/PerimeterXModule/Internals/PxContext.cs index f6532a0..7649f0c 100644 --- a/PerimeterXModule/Internals/PxContext.cs +++ b/PerimeterXModule/Internals/PxContext.cs @@ -44,9 +44,7 @@ public class PxContext public bool IsMobileRequest { get; set; } public string MobileHeader { get; set; } public string[] CookieNames; - public string VidSource { get; set; } - public string Pxhd { get; set; } - public bool IsPxdeVerified { get; set; } + public bool IsPxdeVerified { get; set; } public dynamic Pxde { get; set; } public PxContext(HttpContext context, PxModuleConfigurationSection pxConfiguration) @@ -148,15 +146,7 @@ public PxContext(HttpContext context, PxModuleConfigurationSection pxConfigurati PxCookies[key] = contextCookie.Get(key).Value; } } - if (PxCookies.ContainsKey(PxConstants.VID_COOKIE_PREFIX)) - { - Vid = PxCookies[PxConstants.VID_COOKIE_PREFIX]; - VidSource = PxConstants.VID_COOKIE; - } - if (PxCookies.ContainsKey(PxConstants.PXHD_COOKIE_PREFIX)) - { - Pxhd = PxCookies[PxConstants.PXHD_COOKIE_PREFIX]; - } + DataEnrichmentCookie deCookie = PxCookieUtils.GetDataEnrichmentCookie(PxCookies, pxConfiguration.CookieKey); IsPxdeVerified = deCookie.IsValid; Pxde = deCookie.JsonPayload; diff --git a/PerimeterXModule/Internals/Validators/PXCookieValidator.cs b/PerimeterXModule/Internals/Validators/PXCookieValidator.cs index b0a095e..71b77f2 100644 --- a/PerimeterXModule/Internals/Validators/PXCookieValidator.cs +++ b/PerimeterXModule/Internals/Validators/PXCookieValidator.cs @@ -71,7 +71,6 @@ public virtual bool Verify(PxContext context, IPxCookie pxCookie) context.Score = pxCookie.Score; context.UUID = pxCookie.Uuid; context.Vid = pxCookie.Vid; - context.VidSource = PxConstants.RISK_COOKIE; context.BlockAction = pxCookie.BlockAction; context.PxCookieHmac = pxCookie.Hmac; diff --git a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs index 418d90f..a0b598f 100644 --- a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs +++ b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs @@ -26,15 +26,6 @@ public bool VerifyS2S(PxContext PxContext) { RiskResponse riskResponse = SendRiskResponse(PxContext); PxContext.MadeS2SCallReason = true; - if (riskResponse.Vid != null) - { - PxContext.Vid = riskResponse.Vid; - } - if (riskResponse.Pxhd != null) - { - PxContext.Pxhd = riskResponse.Pxhd; - } - if (riskResponse.Score >= 0 && !string.IsNullOrEmpty(riskResponse.RiskResponseAction)) { int score = riskResponse.Score; @@ -99,6 +90,7 @@ public RiskResponse SendRiskResponse(PxContext PxContext) RiskRequest riskRequest = new RiskRequest { + Vid = PxContext.Vid, Request = Request.CreateRequestFromContext(PxContext), Additional = new Additional { @@ -120,11 +112,6 @@ public RiskResponse SendRiskResponse(PxContext PxContext) riskRequest.Vid = PxContext.Vid; } - if (!string.IsNullOrEmpty(PxContext.Pxhd)) - { - riskRequest.Pxhd = PxContext.Pxhd; - } - if (!string.IsNullOrEmpty(PxContext.UUID)) { riskRequest.UUID = PxContext.UUID; diff --git a/PerimeterXModule/PxModule.cs b/PerimeterXModule/PxModule.cs index 3f49d39..3b586a5 100644 --- a/PerimeterXModule/PxModule.cs +++ b/PerimeterXModule/PxModule.cs @@ -251,8 +251,7 @@ private void PostBlockActivity(PxContext pxContext) BlockUuid = pxContext.UUID, ModuleVersion = PxConstants.MODULE_VERSION, RiskScore = pxContext.Score, - RiskRoundtripTime = pxContext.RiskRoundtripTime, - BlockAction = pxContext.BlockAction + RiskRoundtripTime = pxContext.RiskRoundtripTime }); } } @@ -315,11 +314,6 @@ private void PostActivity(PxContext pxContext, string eventType, ActivityDetails { activity.HttpMethod = "Post"; } - if ((eventType.Equals("page_requested") || eventType.Equals("block")) && (!string.IsNullOrEmpty(pxContext.Pxhd))) - { - activity.pxhd = pxContext.Pxhd; - } - if (!string.IsNullOrEmpty(pxContext.Vid)) { @@ -361,8 +355,6 @@ public static void ResponseBlockPage(PxContext pxContext, PxModuleConfigurationS TemplateFactory.getTemplate(template, config, pxContext.UUID, pxContext.Vid, pxContext.IsMobileRequest, pxContext.BlockAction); pxContext.ApplicationContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; - - if (pxContext.IsMobileRequest) { pxContext.ApplicationContext.Response.ContentType = "application/json"; @@ -384,15 +376,6 @@ public static void ResponseBlockPage(PxContext pxContext, PxModuleConfigurationS pxContext.ApplicationContext.Response.Write(content); } - private static void SetPxhdAndVid(PxContext pxContext) - { - - if (!string.IsNullOrEmpty(pxContext.Pxhd)) - { - pxContext.ApplicationContext.Response.AddHeader("Set-Cookie", PxConstants.PXHD_COOKIE_PREFIX + "=" + pxContext.Pxhd); - } - } - public void Dispose() { if (httpHandler != null) @@ -523,7 +506,6 @@ private void HandleVerification(HttpApplication application) PxLoggingUtils.LogDebug(string.Format("Invalid request to {0}", application.Context.Request.RawUrl)); PostBlockActivity(pxContext); } - SetPxhdAndVid(pxContext); // If implemented, run the customVerificationHandler. if (!string.IsNullOrEmpty(customVerificationHandler)) From 841b4c2d3199a8c25a82bb33d0eb8ad587d973b1 Mon Sep 17 00:00:00 2001 From: Ilai Fallach Date: Thu, 3 Jan 2019 11:09:20 +0200 Subject: [PATCH 17/28] Dev app 1656 custom redirect block page (#57) * wip finished basic structure * [FIX] feature to work. * [ADD] custom block url to whitelist. * [UPDATE] readme with custom block url redirect. * [FIX] pr review. --- .../Internals/Helpers/HttpHandler.cs | 2 +- PerimeterXModule/Internals/PxBlock.cs | 158 ++++++++++++++++++ PerimeterXModule/Internals/PxContext.cs | 5 + PerimeterXModule/Internals/TemplateFactory.cs | 118 +++++++------ .../Internals/Templates/IJsonResponse.cs | 6 + .../Internals/Templates/JsonResponse.cs | 21 +++ .../Internals/Templates/ratelimit.mustache | 9 + PerimeterXModule/PerimeterXModule.csproj | 3 + PerimeterXModule/PxModule.cs | 50 +----- .../PxModuleConfigurationSection.cs | 29 ++++ README.md | 56 ++++++- 11 files changed, 351 insertions(+), 106 deletions(-) create mode 100644 PerimeterXModule/Internals/PxBlock.cs create mode 100644 PerimeterXModule/Internals/Templates/IJsonResponse.cs create mode 100644 PerimeterXModule/Internals/Templates/JsonResponse.cs create mode 100644 PerimeterXModule/Internals/Templates/ratelimit.mustache diff --git a/PerimeterXModule/Internals/Helpers/HttpHandler.cs b/PerimeterXModule/Internals/Helpers/HttpHandler.cs index d1bfe1a..0ba60bd 100644 --- a/PerimeterXModule/Internals/Helpers/HttpHandler.cs +++ b/PerimeterXModule/Internals/Helpers/HttpHandler.cs @@ -38,7 +38,7 @@ public string Post(string requestJson, string uri) } } - public void Dispose() + public void Dispose() { this.httpClient.Dispose(); this.httpClient = null; diff --git a/PerimeterXModule/Internals/PxBlock.cs b/PerimeterXModule/Internals/PxBlock.cs new file mode 100644 index 0000000..187f52e --- /dev/null +++ b/PerimeterXModule/Internals/PxBlock.cs @@ -0,0 +1,158 @@ +using Jil; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace PerimeterX.Internals +{ + class PxBlock + { + private HttpClient httpClient; + + public PxBlock(PxModuleConfigurationSection config) + { + if (config.CustomBlockUrl != null) + { + this.httpClient = PxConstants.CreateHttpClient(false, config.ApiTimeout, false, config); + } + } + + public bool IsJsonResponse(PxContext pxContext) + { + Dictionary headers = pxContext.GetHeadersAsDictionary(); + string jsonHeader; + bool jsonHeaderExists = headers.TryGetValue("accept", out jsonHeader) || headers.TryGetValue("content-type", out jsonHeader); + if (jsonHeaderExists) + { + string[] values = jsonHeader.Split(','); + if (Array.Exists(values, "application/json")) + { + return true; + } + } + + return false; + } + + public string injectCaptchaScript(string vid, string uuid) + { + return ""; + } + + public void ResponseBlockPage(PxContext pxContext, PxModuleConfigurationSection config) + { + string template = "block_template"; + + if (pxContext.BlockAction == "r") + { + template = "ratelimit"; + } + + // In the case of a challenge, the challenge response is taken directly from BlockData. Otherwise, generate html template. + string content = pxContext.BlockAction == "j" && !string.IsNullOrEmpty(pxContext.BlockData) ? pxContext.BlockData : + TemplateFactory.getTemplate(template, config, pxContext.UUID, pxContext.Vid, pxContext.IsMobileRequest, pxContext.BlockAction); + + pxContext.ApplicationContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + + if (pxContext.IsMobileRequest) + { + pxContext.ApplicationContext.Response.ContentType = "application/json"; + using (var output = new StringWriter()) + { + JSON.Serialize( + new MobileResponse() + { + AppId = config.AppId, + Uuid = pxContext.UUID, + Action = pxContext.MapBlockAction(), + Vid = pxContext.Vid, + Page = Convert.ToBase64String(Encoding.UTF8.GetBytes(content)), + CollectorUrl = string.Format(config.CollectorUrl, config.AppId) + }, output); + content = output.ToString(); + } + + pxContext.ApplicationContext.Response.Write(content); + return; + } + + // json response + if (IsJsonResponse(pxContext)) + { + pxContext.ApplicationContext.Response.ContentType = "application/json"; + using (var output = new StringWriter()) + { + var props = TemplateFactory.getProps(config, pxContext.UUID, pxContext.Vid, pxContext.IsMobileRequest, pxContext.BlockAction); + JSON.Serialize( + new JsonResponse() + { + AppId = config.AppId, + Uuid = pxContext.UUID, + Vid = pxContext.Vid, + JsClientSrc = props["jsClientSrc"], + HostUrl = props["hostUrl"], + BlockScript = props["blockScript"] + }, output); + content = output.ToString(); + } + + pxContext.ApplicationContext.Response.Write(content); + return; + } + + if (pxContext.BlockAction != "c" && pxContext.BlockAction != "b") + { + if (pxContext.BlockAction == "r") + { + pxContext.ApplicationContext.Response.StatusCode = 429; // HTTP/1.1 429 TooManyRequests + } + + pxContext.ApplicationContext.Response.Write(content); + return; + } + + if (pxContext.CustomBlockUrl != "") + { + if (pxContext.RedirectOnCustomUrl) + { + string uri = pxContext.ApplicationContext.Request.Url.AbsoluteUri; + string encodedUri = Convert.ToBase64String(Encoding.UTF8.GetBytes(uri)); + string redirectUrl = string.Format("{0}?url={1}&uuid={2}&vid={3}", pxContext.CustomBlockUrl, encodedUri, pxContext.UUID, pxContext.Vid); + PxLoggingUtils.LogDebug("Redirecting to custom block page: " + redirectUrl); + pxContext.ApplicationContext.Response.Redirect(redirectUrl); + return; + } + + HttpResponseMessage response = httpClient.GetAsync(pxContext.CustomBlockUrl).Result; + if ((int)response.StatusCode >= 300) + { + pxContext.ApplicationContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; + pxContext.ApplicationContext.Response.Write("Unable to fetch custom block url. Status: " + response.StatusCode.ToString()); + return; + } + + content = response.Content.ReadAsStringAsync().Result; + if (pxContext.BlockAction == "c") + { + PxLoggingUtils.LogDebug("Injecting captcha to page"); + StringBuilder builder = new StringBuilder(content); + builder.Replace("", injectCaptchaScript(pxContext.Vid, pxContext.UUID) + ""); + builder.Replace("::BLOCK_REF::", pxContext.UUID); + content = builder.ToString(); + } + + pxContext.ApplicationContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + pxContext.ApplicationContext.Response.Write(content); + return; + } + + PxLoggingUtils.LogDebug("Enforcing action: " + pxContext.MapBlockAction() + " page is served"); + pxContext.ApplicationContext.Response.Write(content); + } + } +} diff --git a/PerimeterXModule/Internals/PxContext.cs b/PerimeterXModule/Internals/PxContext.cs index 7649f0c..bb0788e 100644 --- a/PerimeterXModule/Internals/PxContext.cs +++ b/PerimeterXModule/Internals/PxContext.cs @@ -46,6 +46,8 @@ public class PxContext public string[] CookieNames; public bool IsPxdeVerified { get; set; } public dynamic Pxde { get; set; } + public string CustomBlockUrl { get; set; } + public bool RedirectOnCustomUrl { get; set; } public PxContext(HttpContext context, PxModuleConfigurationSection pxConfiguration) { @@ -167,6 +169,9 @@ public PxContext(HttpContext context, PxModuleConfigurationSection pxConfigurati HttpMethod = context.Request.HttpMethod; SensitiveRoute = CheckSensitiveRoute(pxConfiguration.SensitiveRoutes, Uri); + + CustomBlockUrl = pxConfiguration.CustomBlockUrl; + RedirectOnCustomUrl = pxConfiguration.RedirectOnCustomUrl; } private string[] extractCookieNames(string cookieHeader) diff --git a/PerimeterXModule/Internals/TemplateFactory.cs b/PerimeterXModule/Internals/TemplateFactory.cs index 56ae608..bc25d9a 100644 --- a/PerimeterXModule/Internals/TemplateFactory.cs +++ b/PerimeterXModule/Internals/TemplateFactory.cs @@ -8,70 +8,68 @@ namespace PerimeterX { - abstract class TemplateFactory - { - private static readonly string CLIENT_SRC_FP = "/{0}/init.js"; - private static readonly string CLIENT_SRC_TP = "{0}/{1}/main.min.js"; - private static readonly string CAPTCHA_QUERY_PARAMS = "?a={0}&u={1}&v={2}&m={3}"; - private static readonly string CAPTCHA_SRC_FP = "/{0}/captcha/captcha.js{1}"; - private static readonly string CAPTCHA_SRC_TP = "{0}/{1}/captcha.js{2}"; - private static readonly string HOST_FP = "/{0}/xhr"; + abstract class TemplateFactory + { + private static readonly string CLIENT_SRC_FP = "/{0}/init.js"; + private static readonly string CLIENT_SRC_TP = "{0}/{1}/main.min.js"; + private static readonly string CAPTCHA_QUERY_PARAMS = "?a={0}&u={1}&v={2}&m={3}"; + private static readonly string CAPTCHA_SRC_FP = "/{0}/captcha/captcha.js{1}"; + private static readonly string CAPTCHA_SRC_TP = "{0}/{1}/captcha.js{2}"; + private static readonly string HOST_FP = "/{0}/xhr"; + public static string getTemplate(string template, PxModuleConfigurationSection pxConfiguration, string uuid, string vid, bool isMobileRequest, string action) + { + PxLoggingUtils.LogDebug(string.Format("Using {0} template", template)); + string templateStr = getTemplateString(template); + return Render.StringToString(templateStr, getProps(pxConfiguration, uuid, vid, isMobileRequest, action)); + } - public static string getTemplate(string template, PxModuleConfigurationSection pxConfiguration, string uuid, string vid, bool isMobileRequest,string action) - { - PxLoggingUtils.LogDebug(string.Format("Using {0} template", template)); - string templateStr = getTemplateString(template); - return Render.StringToString(templateStr, getProps(pxConfiguration, uuid, vid, isMobileRequest, action)); + private static string getTemplateString(string template) + { + string templateStr = ""; + Assembly _assembly = Assembly.GetExecutingAssembly(); + StreamReader _textStream = new StreamReader(_assembly.GetManifestResourceStream(string.Format("PerimeterX.Internals.Templates.{0}.mustache", template))); - } + while (_textStream.Peek() != -1) + { + templateStr = string.Concat(templateStr, _textStream.ReadLine()); + } + if (string.IsNullOrEmpty(templateStr)) + { + throw new Exception(string.Format("Unable to read template {0} from asm", template)); + } - private static string getTemplateString(string template) - { - string templateStr = ""; - Assembly _assembly = Assembly.GetExecutingAssembly(); - StreamReader _textStream = new StreamReader(_assembly.GetManifestResourceStream(string.Format("PerimeterX.Internals.Templates.{0}.mustache", template))); + return templateStr; + } - while (_textStream.Peek() != -1) - { - templateStr = string.Concat(templateStr, _textStream.ReadLine()); - } - if (string.IsNullOrEmpty(templateStr)) - { - throw new Exception(string.Format("Unable to read template {0} from asm", template)); - } + public static IDictionary getProps(PxModuleConfigurationSection pxConfiguration, string uuid, string vid, bool isMobileRequest, string action) + { + IDictionary props = new Dictionary(); + string captchaParams = string.Format(CAPTCHA_QUERY_PARAMS, action, uuid, vid, isMobileRequest ? "1" : "0"); + props.Add("refId", uuid); + props.Add("appId", pxConfiguration.AppId); + props.Add("vid", vid); + props.Add("uuid", uuid); + props.Add("customLogo", pxConfiguration.CustomLogo); + props.Add("cssRef", pxConfiguration.CssRef); + props.Add("jsRef", pxConfiguration.JsRef); + props.Add("logoVisibility", string.IsNullOrEmpty(pxConfiguration.CustomLogo) ? "hidden" : "visible"); - return templateStr; - } - - private static IDictionary getProps(PxModuleConfigurationSection pxConfiguration, string uuid, string vid, bool isMobileRequest, string action) - { - IDictionary props = new Dictionary(); - string captchaParams = string.Format(CAPTCHA_QUERY_PARAMS, action, uuid, vid, isMobileRequest ? "1" : "0"); - props.Add("refId", uuid); - props.Add("appId", pxConfiguration.AppId); - props.Add("vid", vid); - props.Add("uuid", uuid); - props.Add("customLogo", pxConfiguration.CustomLogo); - props.Add("cssRef", pxConfiguration.CssRef); - props.Add("jsRef", pxConfiguration.JsRef); - props.Add("logoVisibility", string.IsNullOrEmpty(pxConfiguration.CustomLogo) ? "hidden" : "visible"); - - if (pxConfiguration.FirstPartyEnabled && !isMobileRequest) - { - props.Add("jsClientSrc", string.Format(CLIENT_SRC_FP, pxConfiguration.AppId.Substring(2))); - props.Add("blockScript", string.Format(CAPTCHA_SRC_FP, pxConfiguration.AppId.Substring(2), captchaParams)); - props.Add("hostUrl", string.Format(HOST_FP, pxConfiguration.AppId.Substring(2))); - props.Add("firstPartyEnabled", "true"); - } - else - { - props.Add("jsClientSrc", string.Format(CLIENT_SRC_TP, Regex.Replace(pxConfiguration.ClientHostUrl, "https?:", ""), pxConfiguration.AppId)); - props.Add("hostUrl", string.Format(pxConfiguration.CollectorUrl, pxConfiguration.AppId)); - props.Add("blockScript", string.Format(CAPTCHA_SRC_TP, pxConfiguration.CaptchaHostUrl, pxConfiguration.AppId, captchaParams)); - props.Add("firstPartyEnabled", "false"); - } - return props; - } - } + if (pxConfiguration.FirstPartyEnabled && !isMobileRequest) + { + props.Add("jsClientSrc", string.Format(CLIENT_SRC_FP, pxConfiguration.AppId.Substring(2))); + props.Add("blockScript", string.Format(CAPTCHA_SRC_FP, pxConfiguration.AppId.Substring(2), captchaParams)); + props.Add("hostUrl", string.Format(HOST_FP, pxConfiguration.AppId.Substring(2))); + props.Add("firstPartyEnabled", "true"); + } + else + { + props.Add("jsClientSrc", string.Format(CLIENT_SRC_TP, Regex.Replace(pxConfiguration.ClientHostUrl, "https?:", ""), pxConfiguration.AppId)); + props.Add("hostUrl", string.Format(pxConfiguration.CollectorUrl, pxConfiguration.AppId)); + props.Add("blockScript", string.Format(CAPTCHA_SRC_TP, pxConfiguration.CaptchaHostUrl, pxConfiguration.AppId, captchaParams)); + props.Add("firstPartyEnabled", "false"); + } + return props; + } + } } diff --git a/PerimeterXModule/Internals/Templates/IJsonResponse.cs b/PerimeterXModule/Internals/Templates/IJsonResponse.cs new file mode 100644 index 0000000..f68565e --- /dev/null +++ b/PerimeterXModule/Internals/Templates/IJsonResponse.cs @@ -0,0 +1,6 @@ +namespace PerimeterX +{ + interface IJsonResponse + { + } +} diff --git a/PerimeterXModule/Internals/Templates/JsonResponse.cs b/PerimeterXModule/Internals/Templates/JsonResponse.cs new file mode 100644 index 0000000..f42698f --- /dev/null +++ b/PerimeterXModule/Internals/Templates/JsonResponse.cs @@ -0,0 +1,21 @@ +using System.Runtime.Serialization; + +namespace PerimeterX +{ + [DataContract] + class JsonResponse : IJsonResponse + { + [DataMember(Name = "appId")] + public string AppId; + [DataMember(Name = "jsClientSrc")] + public string JsClientSrc; + [DataMember(Name = "uuid")] + public string Uuid; + [DataMember(Name = "vid")] + public string Vid; + [DataMember(Name = "hostUrl")] + public string HostUrl; + [DataMember(Name = "blockScript")] + public string BlockScript; + } +} diff --git a/PerimeterXModule/Internals/Templates/ratelimit.mustache b/PerimeterXModule/Internals/Templates/ratelimit.mustache new file mode 100644 index 0000000..36fd393 --- /dev/null +++ b/PerimeterXModule/Internals/Templates/ratelimit.mustache @@ -0,0 +1,9 @@ + + + Too Many Requests + + +

Too Many Requests

+

Reached maximum requests limitation, try again soon.

+ + \ No newline at end of file diff --git a/PerimeterXModule/PerimeterXModule.csproj b/PerimeterXModule/PerimeterXModule.csproj index 0682d02..00401f2 100644 --- a/PerimeterXModule/PerimeterXModule.csproj +++ b/PerimeterXModule/PerimeterXModule.csproj @@ -63,6 +63,7 @@ + @@ -80,7 +81,9 @@ + + diff --git a/PerimeterXModule/PxModule.cs b/PerimeterXModule/PxModule.cs index 3b586a5..7529ce7 100644 --- a/PerimeterXModule/PxModule.cs +++ b/PerimeterXModule/PxModule.cs @@ -36,6 +36,8 @@ using System.Reflection; using System.Collections; using Jil; +using System.Collections.Generic; +using PerimeterX.Internals; namespace PerimeterX { @@ -49,6 +51,7 @@ public class PxModule : IHttpModule private readonly IPXCookieValidator PxCookieValidator; private readonly IPXS2SValidator PxS2SValidator; private readonly IReverseProxy ReverseProxy; + private readonly PxBlock pxBlock; private readonly bool enabled; private readonly bool sendPageActivites; @@ -145,6 +148,8 @@ public PxModule() // Build reverse proxy ReverseProxy = new ReverseProxy(config); + pxBlock = new PxBlock(config); + PxLoggingUtils.LogDebug(ModuleName + " initialized"); } @@ -323,7 +328,7 @@ private void PostActivity(PxContext pxContext, string eventType, ActivityDetails reporter.Post(activity); } - public static void BlockRequest(PxContext pxContext, PxModuleConfigurationSection config) + public void BlockRequest(PxContext pxContext, PxModuleConfigurationSection config) { pxContext.ApplicationContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; pxContext.ApplicationContext.Response.TrySkipIisCustomErrors = true; @@ -333,49 +338,10 @@ public static void BlockRequest(PxContext pxContext, PxModuleConfigurationSectio } else { - ResponseBlockPage(pxContext, config); + pxBlock.ResponseBlockPage(pxContext, config); } } - public static void ResponseBlockPage(PxContext pxContext, PxModuleConfigurationSection config) - { - string template = "block_template"; - - if (pxContext.BlockAction == "j") - { - template = "challenge"; - } - else if (pxContext.BlockAction == "b") - { - template = "block"; - } - - // In the case of a challenge, the challenge response is taken directly from BlockData. Otherwise, generate html template. - string content = template == "challenge" && !string.IsNullOrEmpty(pxContext.BlockData) ? pxContext.BlockData : - TemplateFactory.getTemplate(template, config, pxContext.UUID, pxContext.Vid, pxContext.IsMobileRequest, pxContext.BlockAction); - - pxContext.ApplicationContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; - if (pxContext.IsMobileRequest) - { - pxContext.ApplicationContext.Response.ContentType = "application/json"; - using (var output = new StringWriter()) - { - JSON.Serialize( - new MobileResponse() - { - AppId = config.AppId, - Uuid = pxContext.UUID, - Action = pxContext.MapBlockAction(), - Vid = pxContext.Vid, - Page = Convert.ToBase64String(Encoding.UTF8.GetBytes(content)), - CollectorUrl = string.Format(config.CollectorUrl, config.AppId) - }, output); - content = output.ToString(); - } - } - pxContext.ApplicationContext.Response.Write(content); - } - public void Dispose() { if (httpHandler != null) @@ -415,7 +381,7 @@ private bool IsFilteredRequest(HttpContext context) { foreach (var prefix in routesWhitelist) { - if (url.StartsWith(prefix)) + if (url.StartsWith(prefix) || url == pxContext.CustomBlockUrl) { return true; } diff --git a/PerimeterXModule/PxModuleConfigurationSection.cs b/PerimeterXModule/PxModuleConfigurationSection.cs index 6696785..341d3ab 100644 --- a/PerimeterXModule/PxModuleConfigurationSection.cs +++ b/PerimeterXModule/PxModuleConfigurationSection.cs @@ -507,6 +507,7 @@ public string ClientHostUrl this["clientHostUrl"] = value; } } + [ConfigurationProperty("captchaHostUrl", DefaultValue = "https://captcha.perimeterx.net")] public string CaptchaHostUrl { @@ -520,6 +521,34 @@ public string CaptchaHostUrl this["captchaHostUrl"] = value; } } + + [ConfigurationProperty("customBlockUrl", DefaultValue = null)] + public string CustomBlockUrl + { + get + { + return (string)this["customBlockUrl"]; + } + + set + { + this["customBlockUrl"] = value; + } + } + + [ConfigurationProperty("redirectOnCustomUrl", DefaultValue = false)] + public bool RedirectOnCustomUrl + { + get + { + return (bool)this["redirectOnCustomUrl"]; + } + + set + { + this["redirectOnCustomUrl"] = value; + } + } } } diff --git a/README.md b/README.md index e9a30f3..245cd1c 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Table of Contents * [Send Page Activities](#send-page-activities) * [Monitor Mode](#monitor-mode) * [Base URI](#base-uri) + * [Customize Default Block Page](#customize-block-page) * [Override UA header](#override-ua) **[Contributing](#contributing)** @@ -107,8 +108,9 @@ Configuration options are set in `pxModuleConfigurationSection` - apiToken #### Customizing Default Block Pages -###### Custom Logo -Adding a custom logo to the blocking page is by providing the pxConfig a key ```customLogo``` , the logo will be displayed at the top div of the the block page The logo's ```max-heigh``` property would be 150px and width would be set to ```auto``` + +##### Custom Logo +Adding a custom logo to the blocking page is by providing the pxConfig a key ```customLogo``` , the logo will be displayed at the top div of the the block page The logo's ```max-height``` property would be 150px and width would be set to ```auto``` The key ```customLogo``` expects a valid URL address such as ```https://s.perimeterx.net/logo.png``` @@ -119,7 +121,7 @@ Example below: ... ``` -Custom JS/CSS +##### Custom JS/CSS The block page can be modified with a custom CSS by adding to the ```pxConfig``` the key ```cssRef``` and providing a valid URL to the css In addition there is also the option to add a custom JS file by adding ```jsRef``` key to the ```pxConfig``` and providing the JS file that will be loaded with the block page, this key also expects a valid URL @@ -132,6 +134,54 @@ Example below: cssRef="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" ... ``` + +##### Redirect to a Custom Block Page URL +Customizes the block page to meet branding and message requirements by specifying the URL of the block page HTML file. The page can also implement CAPTCHA. + +**Default:** "" (empty string) + +Example: + +```xml +customBlockUrl = "http://sub.domain.com/block.html" +``` + +> Note: This URI is whitelisted automatically to avoid infinite redirects. + +##### Redirect on Custom URL + +The `redirectOnCustomUrl` boolean flag to redirect users to a block page. + +**Default:** false + +Example: + +```xml + redirectOnCustomUrl = "false" +``` + +By default, when a user exceeds the blocking threshold and blocking is enabled, the user is redirected to the block page defined by the `customBlockUrl` variable. The defined block page displays a **307 (Temporary Redirect)** HTTP Response Code. + +When the flag is set to false, a **403 (Unauthorized)** HTTP Response Code is displayed on the blocked page URL. + + +Setting the flag to true (enabling redirects) results in the following URL upon blocking: + +``` +http://www.example.com/block.html?url=L3NvbWVwYWdlP2ZvbyUzRGJhcg==&uuid=e8e6efb0-8a59-11e6-815c-3bdad80c1d39&vid=08320300-6516-11e6-9308-b9c827550d47 +``` + +Setting the flag to false does not require the block page to include any of the examples below, as they are injected into the blocking page via the PerimeterX ASP.NET Enforcer. + +> NOTE: The `url` parameter should be built with the URL *Encoded* query parameters (of the original request) with both the original path and variables Base64 Encoded (to avoid collisions with block page query params). + +##### Custom Block Pages Requirements + +As of version 2.8.0, Captcha logic is being handled through the JavaScript snippet and not through the Enforcer. + +Users who have Custom Block Pages must include the new script tag and a new div in the _.html_ block page. + + #### Changing the Minimum Score for Blocking **default:** 100 From 6d36076a0dd814a1df429cbb56fc6bdebdf2a9f4 Mon Sep 17 00:00:00 2001 From: alexbpx <41577203+alexbpx@users.noreply.github.com> Date: Sun, 6 Jan 2019 18:16:21 +0200 Subject: [PATCH 18/28] Added pxhd (#58) * Added pxhd * Fixed pxBlock * Update ActivityDetails.cs * Added "pxvid" cookie parsing --- .../DataContracts/Activities/Activity.cs | 3 +++ .../Activities/ActivityDetails.cs | 8 +++++-- .../DataContracts/Requests/RiskRequest.cs | 6 ++++++ .../DataContracts/Responses/RiskResponse.cs | 4 ++++ .../Internals/Helpers/PxConstants.cs | 6 +++++- PerimeterXModule/Internals/PxBlock.cs | 2 +- PerimeterXModule/Internals/PxContext.cs | 18 +++++++++++++++- .../Internals/Validators/PXCookieValidator.cs | 1 + .../Internals/Validators/PXS2SValidator.cs | 15 ++++++++++--- PerimeterXModule/PxModule.cs | 21 +++++++++++++++++-- 10 files changed, 74 insertions(+), 10 deletions(-) diff --git a/PerimeterXModule/DataContracts/Activities/Activity.cs b/PerimeterXModule/DataContracts/Activities/Activity.cs index 249d9d6..50fd441 100644 --- a/PerimeterXModule/DataContracts/Activities/Activity.cs +++ b/PerimeterXModule/DataContracts/Activities/Activity.cs @@ -32,5 +32,8 @@ public class Activity [DataMember(Name = "http_method", EmitDefaultValue = false)] public string HttpMethod; + + [DataMember(Name = "pxhd", EmitDefaultValue = false)] + public string Pxhd; } } diff --git a/PerimeterXModule/DataContracts/Activities/ActivityDetails.cs b/PerimeterXModule/DataContracts/Activities/ActivityDetails.cs index a994034..426e049 100644 --- a/PerimeterXModule/DataContracts/Activities/ActivityDetails.cs +++ b/PerimeterXModule/DataContracts/Activities/ActivityDetails.cs @@ -31,7 +31,11 @@ public class ActivityDetails : IActivityDetails [DataMember(Name = "risk_rtt")] public long RiskRoundtripTime; - } + + [DataMember(Name = "block_action")] + public string BlockAction; + + } [DataContract] public class EnforcerTelemetryActivityDetails : IActivityDetails @@ -51,4 +55,4 @@ public class EnforcerTelemetryActivityDetails : IActivityDetails [DataMember(Name = "enforcer_configs")] public string EnforcerConfigs; } -} \ No newline at end of file +} diff --git a/PerimeterXModule/DataContracts/Requests/RiskRequest.cs b/PerimeterXModule/DataContracts/Requests/RiskRequest.cs index 3946a4c..a6925fb 100644 --- a/PerimeterXModule/DataContracts/Requests/RiskRequest.cs +++ b/PerimeterXModule/DataContracts/Requests/RiskRequest.cs @@ -19,5 +19,11 @@ public class RiskRequest [DataMember(Name = "additional", EmitDefaultValue = false)] public Additional Additional; + + [DataMember(Name = "pxhd", EmitDefaultValue = false)] + public string Pxhd; + + [DataMember(Name = "vid_source", EmitDefaultValue = false)] + public string VidSource; } } diff --git a/PerimeterXModule/DataContracts/Responses/RiskResponse.cs b/PerimeterXModule/DataContracts/Responses/RiskResponse.cs index 5836175..84697d7 100644 --- a/PerimeterXModule/DataContracts/Responses/RiskResponse.cs +++ b/PerimeterXModule/DataContracts/Responses/RiskResponse.cs @@ -28,6 +28,10 @@ public class RiskResponse [DataMember(Name = "data_enrichment")] public object DataEnrichment; + + [DataMember(Name = "pxhd")] + public string Pxhd; + } diff --git a/PerimeterXModule/Internals/Helpers/PxConstants.cs b/PerimeterXModule/Internals/Helpers/PxConstants.cs index 2bc7c01..e6ea3d0 100644 --- a/PerimeterXModule/Internals/Helpers/PxConstants.cs +++ b/PerimeterXModule/Internals/Helpers/PxConstants.cs @@ -10,10 +10,14 @@ namespace PerimeterX public static class PxConstants { public static readonly string HEX_ALPHABET = "0123456789abcdef"; - public static readonly string[] PX_COOKIES_PREFIX = { COOKIE_V1_PREFIX, COOKIE_V3_PREFIX, COOKIE_DATA_ENRICHMENT_PREFIX }; + public static readonly string[] PX_COOKIES_PREFIX = { COOKIE_V1_PREFIX, COOKIE_V3_PREFIX, COOKIE_DATA_ENRICHMENT_PREFIX, COOKIE_PXHD_PREFIX, COOKIE_VID_PREFIX, "_" + COOKIE_VID_PREFIX }; public static readonly string[] PX_TOKEN_PREFIX = { TOKEN_V1_PREFIX, TOKEN_V3_PREFIX }; public const string COOKIE_V1_PREFIX = "_px"; public const string COOKIE_V3_PREFIX = "_px3"; + public const string COOKIE_PXHD_PREFIX = "_pxhd"; + public const string COOKIE_VID_PREFIX = "pxvid"; + public const string VID_COOKIE = "vid_cookie"; + public const string RISK_COOKIE = "risk_cookie"; public const string COOKIE_DATA_ENRICHMENT_PREFIX = "_pxde"; public const string TOKEN_V1_PREFIX = "1"; public const string TOKEN_V3_PREFIX = "3"; diff --git a/PerimeterXModule/Internals/PxBlock.cs b/PerimeterXModule/Internals/PxBlock.cs index 187f52e..aa1ca96 100644 --- a/PerimeterXModule/Internals/PxBlock.cs +++ b/PerimeterXModule/Internals/PxBlock.cs @@ -30,7 +30,7 @@ public bool IsJsonResponse(PxContext pxContext) if (jsonHeaderExists) { string[] values = jsonHeader.Split(','); - if (Array.Exists(values, "application/json")) + if (Array.Exists(values, element => element == "application/json")) { return true; } diff --git a/PerimeterXModule/Internals/PxContext.cs b/PerimeterXModule/Internals/PxContext.cs index bb0788e..8e47891 100644 --- a/PerimeterXModule/Internals/PxContext.cs +++ b/PerimeterXModule/Internals/PxContext.cs @@ -46,8 +46,10 @@ public class PxContext public string[] CookieNames; public bool IsPxdeVerified { get; set; } public dynamic Pxde { get; set; } - public string CustomBlockUrl { get; set; } + public string CustomBlockUrl { get; set; } public bool RedirectOnCustomUrl { get; set; } + public string VidSource { get; set; } + public string Pxhd { get; set; } public PxContext(HttpContext context, PxModuleConfigurationSection pxConfiguration) { @@ -152,6 +154,20 @@ public PxContext(HttpContext context, PxModuleConfigurationSection pxConfigurati DataEnrichmentCookie deCookie = PxCookieUtils.GetDataEnrichmentCookie(PxCookies, pxConfiguration.CookieKey); IsPxdeVerified = deCookie.IsValid; Pxde = deCookie.JsonPayload; + if (PxCookies.ContainsKey(PxConstants.COOKIE_VID_PREFIX)) + { + Vid = PxCookies[PxConstants.COOKIE_VID_PREFIX]; + VidSource = PxConstants.VID_COOKIE; + } + if (PxCookies.ContainsKey("_" + PxConstants.COOKIE_VID_PREFIX)) + { + Vid = PxCookies["_" + PxConstants.COOKIE_VID_PREFIX]; + VidSource = PxConstants.VID_COOKIE; + } + if (PxCookies.ContainsKey(PxConstants.COOKIE_PXHD_PREFIX)) + { + Pxhd = PxCookies[PxConstants.COOKIE_PXHD_PREFIX]; + } } Hostname = context.Request.Url.Host; diff --git a/PerimeterXModule/Internals/Validators/PXCookieValidator.cs b/PerimeterXModule/Internals/Validators/PXCookieValidator.cs index 71b77f2..b0a095e 100644 --- a/PerimeterXModule/Internals/Validators/PXCookieValidator.cs +++ b/PerimeterXModule/Internals/Validators/PXCookieValidator.cs @@ -71,6 +71,7 @@ public virtual bool Verify(PxContext context, IPxCookie pxCookie) context.Score = pxCookie.Score; context.UUID = pxCookie.Uuid; context.Vid = pxCookie.Vid; + context.VidSource = PxConstants.RISK_COOKIE; context.BlockAction = pxCookie.BlockAction; context.PxCookieHmac = pxCookie.Hmac; diff --git a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs index a0b598f..e2bd76f 100644 --- a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs +++ b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs @@ -32,6 +32,7 @@ public bool VerifyS2S(PxContext PxContext) PxContext.Score = score; PxContext.UUID = riskResponse.Uuid; PxContext.BlockAction = riskResponse.RiskResponseAction; + PxContext.Pxhd = riskResponse.Pxhd; if (PxContext.BlockAction == PxConstants.JS_CHALLENGE_ACTION && !string.IsNullOrEmpty(riskResponse.RiskResponseActionData.Body)) @@ -87,14 +88,22 @@ public RiskResponse SendRiskResponse(PxContext PxContext) { riskMode = ModuleMode.MONITOR_MODE; } - + string vid = PxContext.Vid; + string pxhd = PxContext.Pxhd; + string callReason = PxContext.S2SCallReason; + if (PxContext.Pxhd != null && PxContext.Vid != null && PxContext.S2SCallReason == "no_cookie") + { + callReason = "no_cookie_w_vid"; + } RiskRequest riskRequest = new RiskRequest { - Vid = PxContext.Vid, + Vid = vid, + Pxhd = pxhd, + VidSource = PxContext.VidSource, Request = Request.CreateRequestFromContext(PxContext), Additional = new Additional { - CallReason = PxContext.S2SCallReason, + CallReason = callReason, ModuleVersion = PxConstants.MODULE_VERSION, HttpMethod = PxContext.HttpMethod, HttpVersion = PxContext.HttpVersion, diff --git a/PerimeterXModule/PxModule.cs b/PerimeterXModule/PxModule.cs index 7529ce7..9049117 100644 --- a/PerimeterXModule/PxModule.cs +++ b/PerimeterXModule/PxModule.cs @@ -252,6 +252,7 @@ private void PostBlockActivity(PxContext pxContext) { PostActivity(pxContext, "block", new ActivityDetails { + BlockAction = pxContext.BlockAction, BlockReason = pxContext.BlockReason, BlockUuid = pxContext.UUID, ModuleVersion = PxConstants.MODULE_VERSION, @@ -313,7 +314,7 @@ private void PostActivity(PxContext pxContext, string eventType, ActivityDetails SocketIP = pxContext.Ip, Url = pxContext.FullUrl, Details = details, - Headers = pxContext.GetHeadersAsDictionary() + Headers = pxContext.GetHeadersAsDictionary(), }; if (eventType.Equals("page_requested")) { @@ -325,6 +326,11 @@ private void PostActivity(PxContext pxContext, string eventType, ActivityDetails activity.Vid = pxContext.Vid; } + if (!string.IsNullOrEmpty(pxContext.Pxhd) && (eventType == "page_requested" || eventType == "block")) + { + activity.Pxhd = pxContext.Pxhd; + } + reporter.Post(activity); } @@ -472,7 +478,8 @@ private void HandleVerification(HttpApplication application) PxLoggingUtils.LogDebug(string.Format("Invalid request to {0}", application.Context.Request.RawUrl)); PostBlockActivity(pxContext); } - + + SetPxhdAndVid(pxContext); // If implemented, run the customVerificationHandler. if (!string.IsNullOrEmpty(customVerificationHandler)) { @@ -496,6 +503,16 @@ private void HandleVerification(HttpApplication application) } } + private static void SetPxhdAndVid(PxContext pxContext) + { + + if (!string.IsNullOrEmpty(pxContext.Pxhd)) + { + string pxhd = PxConstants.COOKIE_PXHD_PREFIX + "=" + pxContext.Pxhd; + pxContext.ApplicationContext.Response.AddHeader("Set-Cookie", pxhd); + } + } + /// /// Uses reflection to check whether an IVerificationHandler was implemented by the customer. /// From 1ccb4c54f08946ed03289399821635daaa0cc445 Mon Sep 17 00:00:00 2001 From: alexbpx <41577203+alexbpx@users.noreply.github.com> Date: Thu, 10 Jan 2019 11:37:09 +0200 Subject: [PATCH 19/28] Removed vid from the assertion of no_cookie_w_vid (#60) --- PerimeterXModule/Internals/Validators/PXS2SValidator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs index e2bd76f..3ae2d55 100644 --- a/PerimeterXModule/Internals/Validators/PXS2SValidator.cs +++ b/PerimeterXModule/Internals/Validators/PXS2SValidator.cs @@ -91,7 +91,7 @@ public RiskResponse SendRiskResponse(PxContext PxContext) string vid = PxContext.Vid; string pxhd = PxContext.Pxhd; string callReason = PxContext.S2SCallReason; - if (PxContext.Pxhd != null && PxContext.Vid != null && PxContext.S2SCallReason == "no_cookie") + if (PxContext.Pxhd != null && PxContext.S2SCallReason == "no_cookie") { callReason = "no_cookie_w_vid"; } From 45023ab1d0114a06127e8058da82098bc2f94472 Mon Sep 17 00:00:00 2001 From: Ilai Fallach Date: Sun, 13 Jan 2019 10:22:24 +0200 Subject: [PATCH 20/28] [FIX] When building a cookie, check if the cookie exists for v3, otherwise return null. (#61) [FIX] Removing escaping from blockScript in mustache. --- PerimeterXModule/Internals/Cookies/PxCookieUtils.cs | 13 ++++++------- .../Internals/Templates/block_template.mustache | 6 +++--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/PerimeterXModule/Internals/Cookies/PxCookieUtils.cs b/PerimeterXModule/Internals/Cookies/PxCookieUtils.cs index 2393b9e..8a35402 100644 --- a/PerimeterXModule/Internals/Cookies/PxCookieUtils.cs +++ b/PerimeterXModule/Internals/Cookies/PxCookieUtils.cs @@ -11,18 +11,17 @@ public static class PxCookieUtils { public static IPxCookie BuildCookie(PxModuleConfigurationSection config, Dictionary cookies, ICookieDecoder cookieDecoder) { - if (cookies.Count == 0) - { - return null; - } - if (cookies.ContainsKey(PxConstants.COOKIE_V1_PREFIX)) { return new PxCookieV1(cookieDecoder, cookies[PxConstants.COOKIE_V1_PREFIX]); } + else if(cookies.ContainsKey(PxConstants.COOKIE_V3_PREFIX)) + { + return new PxCookieV3(cookieDecoder, cookies[PxConstants.COOKIE_V3_PREFIX]); + } - return new PxCookieV3(cookieDecoder, cookies[PxConstants.COOKIE_V3_PREFIX]); - } + return null; + } public static T Deserialize(ICookieDecoder cookieDecoder, string rawCookie) { diff --git a/PerimeterXModule/Internals/Templates/block_template.mustache b/PerimeterXModule/Internals/Templates/block_template.mustache index 0fcbd6c..cedd184 100644 --- a/PerimeterXModule/Internals/Templates/block_template.mustache +++ b/PerimeterXModule/Internals/Templates/block_template.mustache @@ -153,14 +153,14 @@