mirror of
https://github.com/microsoft/BCQuality.git
synced 2026-10-05 14:46:55 +01:00
New remedial article for spotting when AL calls an endpoint that does not authenticate itself to the client (bare HttpClient.Get, blank SOAP SecretText, post-DisableHttpsCheck HTTP) and requires the response to be size-, schema-, and request/response-integrity-validated before it is trusted. Includes the BC-specific false-positive clarifications (platform buffers the full body, so an in-AL size check after buffering is correct; no DNS-rebinding/bounded-read demand; HTTPS not always enforceable) plus good/bad AL samples. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
46 lines
2.3 KiB
AL
46 lines
2.3 KiB
AL
codeunit 50540 "Sec Sample UnauthResp Good"
|
|
{
|
|
// The public VAT validation service does not authenticate itself to us (no OAuth, no
|
|
// certificate, plain HTTP), so its response must be validated before it is trusted.
|
|
procedure IsVatNumberValid(RequestedCountryCode: Text; RequestedVatNumber: Text): Boolean
|
|
var
|
|
HttpClient: HttpClient;
|
|
Response: HttpResponseMessage;
|
|
JsonResponse: JsonObject;
|
|
JsonToken: JsonToken;
|
|
Content: Text;
|
|
ResponseCountryCode: Text;
|
|
ResponseVatNumber: Text;
|
|
begin
|
|
HttpClient.Get('http://vat-service.example/check?cc=' + RequestedCountryCode + '&vat=' + RequestedVatNumber, Response);
|
|
if not Response.IsSuccessStatusCode() then
|
|
exit(false);
|
|
|
|
Response.Content().ReadAs(Content);
|
|
|
|
// 1) Size cap - the platform already buffered the whole body; reject abnormally large payloads.
|
|
if StrLen(Content) > 4096 then
|
|
Error('The VAT validation response exceeded the maximum allowed size and was rejected.');
|
|
|
|
// 2) Schema - require the expected scalar fields, not just a truthy flag.
|
|
if not JsonResponse.ReadFrom(Content) then
|
|
Error('The VAT validation response was not in the expected format and was rejected.');
|
|
if not JsonResponse.Get('countryCode', JsonToken) then
|
|
Error('The VAT validation response did not include the requested identifiers and was rejected.');
|
|
ResponseCountryCode := JsonToken.AsValue().AsText();
|
|
if not JsonResponse.Get('vatNumber', JsonToken) then
|
|
Error('The VAT validation response did not include the requested identifiers and was rejected.');
|
|
ResponseVatNumber := JsonToken.AsValue().AsText();
|
|
|
|
// 3) Integrity - the echoed identifiers must match the request, so a valid=true payload
|
|
// with the identifiers stripped cannot be accepted for an arbitrary VAT number.
|
|
if (UpperCase(ResponseCountryCode) <> UpperCase(RequestedCountryCode)) or
|
|
(UpperCase(ResponseVatNumber) <> UpperCase(RequestedVatNumber))
|
|
then
|
|
Error('The VAT validation response did not match the requested identifiers and was rejected.');
|
|
|
|
if not JsonResponse.Get('valid', JsonToken) then
|
|
exit(false);
|
|
exit(JsonToken.AsValue().AsBoolean());
|
|
end;
|
|
}
|