# Re[mark]able.net: full post archive This file contains the full text of every published post for LLM ingestion. Source: https://www.re-mark-able.net --- # Expose your localhost to Claude and ChatGPT with one line: tapinto.dev URL: https://www.re-mark-able.net/blogs/2026/05/24/tapinto-localhost-tunnels.html Published: 2026-05-24 Tags: Developer Experience, MCP, Claude, ChatGPT, Tunnels If you’ve ever had to test a local dev site on your phone, or point ChatGPT or Claude at an MCP server you’re still iterating on locally, you know the dance. Spin up ngrok or cloudflared, sign up for an account, copy a random URL, paste it into a config somewhere, hope nothing rotated. For one-off work it’s friction. If you want to point Claude or ChatGPT at something you’re building locally, it’s a wall.A few months ago I started using tapinto.dev and the dance is gone. The interface is simple: you ask the agent.One lineIn Claude Code or ChatGPT, with the tapinto MCP installed: “Open a tunnel to localhost:4000.”That’s it. The agent calls the create_tunnel tool, tapinto provisions a named public HTTPS URL, and you get back something like https://my-thing.tapinto.dev. No browser tab, no account creation flow, no copy-paste from a terminal. The tunnel stays open until you stop it or the session ends.To install, head to tapinto.dev and follow the install command. After that your agent has the tool available like any other.Why this is different from ngrok-style toolsMost tunneling tools were built for one use case. You’re a developer, you want to expose a local server so you can test a webhook. Tapinto starts from a different place.The first difference is that tapinto is MCP-aware. If you tunnel something that is an MCP server, tapinto detects it and exposes the right endpoints in the right shape. ChatGPT’s Developer Mode and Claude’s MCP clients can call it directly. No protocol translation, no manual configuration.It’s also free without friction. 60 minutes per week, no credit card. For mobile QA on your own site or quick MCP iteration that’s plenty. If you need more, you pay.Tunnels get readable URLs too. You get https://remarkable-blog.tapinto.dev, not https://e7f9a3.ngrok-free.app. Easier to remember, easier to type on your phone, easier to share with a colleague.And it’s designed to be called by agents, not just by humans. When the main user is an AI agent the requirements are different. You don’t need a polished CLI or a dashboard. You need a tool definition the agent can call.Testing this blog on mobileI’m writing this on the same day I rebuilt this site. To check the layout on my phone, I had Claude Code do:Open a tunnel to http://127.0.0.1:4000.Back came https://remarkable-blog.tapinto.dev. Open that URL on my phone, browse around, find the things that look broken at 375px wide, fix them, refresh on the phone. No deploys, no static-site preview services, no copying anything between machines.When I was done:Close the tunnel.That’s the entire workflow. The hard parts of mobile QA (getting your phone to your laptop) collapse into two sentences.A local MCP server from ChatGPTThe use case I built it for is developing an MCP server. You’re iterating fast, restarting frequently, and the server only exists on your laptop. You want ChatGPT, running in your browser in Developer Mode, to talk to it.Without tunnels you have two bad options. Deploy on every change, or run ChatGPT against a stale snapshot. With tapinto:Open an MCP tunnel to my local server on port 8765.The agent calls the tool, tapinto detects the MCP server, and gives back the public URL plus the registration metadata. You drop the URL into ChatGPT’s MCP configuration once. From that point on, every restart of your local server is invisible to ChatGPT. Same URL, fresh code.That loop, seconds instead of minutes, is what makes local MCP development actually usable.Try itI’ve been using this for a few weeks now. For mobile QA it has saved me enough time that I keep reaching for it. For MCP development it made local iteration actually pleasant. Two minutes to install, and then you forget it’s even there. The agent just handles it.tapinto.dev has the install instructions and the docs. If you do any work where Claude or ChatGPT needs to see something on your laptop, this is worth trying. Let me know what you build with it. --- # What is .NET Aspire? URL: https://www.re-mark-able.net/blogs/2024/04/30/what-is-aspire.html Published: 2024-04-30 Tags: .NET, Aspire If you are a .NET developer you will have probably heard of Aspire. What is Aspire? Yet another framework or a better way of working? I have been using and testing Aspire since the previews and will share some insight into how it has been helpful to me on different projects already. Even though it is still in public preview.What is .NET Aspire all about?So what is Aspire all about? According to Microsoft Learn:“NET Aspire is designed to improve the experience of building .NET cloud-native apps. It provides a consistent, opinionated set of tools and patterns that help you build and run distributed apps.”You will get 3 things right out of the box: CLI tools and Project templates for getting started Orchestration for local dev only Components for consuming external services (databases, caching, messaging)Keep in mind that everything is opt-in with Aspire. If you want to use a component you can but you are not required to. You can always set things up manually if you need to. This helped me to make the switch to Aspire in small steps instead of changing the entire project at once.How to start in an existing project?I get no fun out of copying the docs here on how to start. So for a full explanation of how to get started look at the Microsoft Learn docs. Install the tooling. Create a standard Aspire project with the provided template and all the information below will make sense.For all the JetBrains Rider users there is an awesome plugin available that also handles debugging for you out of the box. You can visit one of the following three links to get more info: Blogpost about the plugin: Blog Rider plugin: Plugin Github: SourceThats all nice and fun for a demo app but how to I add this to my current project? Asuming your project is in a single repository you can do one of the following depending on the tools that you have: Visual studio: Right click > Add Aspire Orchestration. CLI: execute dotnet new aspire-apphost & dotnet new aspire-servicedefaults Rider: Add new project and go to the Aspire templates to add Orchestration and ServiceDefaults projects.For other templates you can have a look hereOrchestration, getting rid of docker compose?The orchestration part is only meant for local development. It is the replacement for your docker compose file that links everything together. If you follow the default template then this is the Aspire.AppHost project. This project will tie everything together. One of the best features of Aspire is that you don’t need to think about ports anymore. Let’s consider the following orchestration in the Program.cs of the Aspire AppHost project and I will explain it afterwards.var builder = DistributedApplication.CreateBuilder(args);// My Redis for caching stuffvar myRedis = builder.AddRedis("myRedisCache");// My APIvar myApi = builder.AddProject<Projects.MyApi>("myApi") .WithReference(myRedis);// React frontendbuilder.AddNpmApp("frontend", "../frontend", "start") .WithReference(myApi) .WithEndpoint(targetPort: 3000, port: 3000, isProxied: false, scheme: "http", env: "PORT") .PublishAsDockerFile();builder.Build().Run();This orchestration consists of 3 parts: Redis cache .NET Web API project React frontendYes, that is correct, any Node project will work with this because Aspire is not .NET only! Simply give the npm run command that is needed to start your frontend. In my case, it is “start”.First I added a Redis cache. This will launch a Redis container in docker to host it. Although we don’t use a compose or docker file anymore. Aspire still requires docker to run things it cannot run in-process (dotnet, npm, etc) like databases, Redis, messaging services, etc. Also, notice the “myRedisCache” name I gave it. This will come back in the configuration later in this blog.Now by adding the dotnet project as “myApi” I also add a reference to myRedis. This will inject myRedis environment variables into MyApi. Therefore my API will know on my local dev where this redis cache is running. It can be a different port every time I run the apphost.In your react frontend you will probably have an env.localhost or env.yourenvironment file. Here you can define environment variables and use them to call your API. Aspire will make sure that those environment variables are available. The format is always the same.MY_API_ENDPOINT=$services__myApi__http__0/api/v2.0/my/callThese few lines of code will be the orchestration of the solution and tie three components together. Let’s take a look at how we can connect to the Redis cache from our API. We do this by using components.Components and a strong opinionated approachAspire components are Nuget packages that simplify your life when connecting to external sources like databases such as Postgres, Cosmos, Redis, etc. There is currently, even though it is still in preview, a big list of already supported components. Now let’s look into how we can use Aspire in our “MyApi” project and how we initialize the Redis cache.First we need to add the so called ServiceDefaults. This is a project template given by Aspire with an opinionated way to set up logging, tracing, and metrics with OpenTelemetry. This will set up everything for you to work perfectly with the Aspire Dashboard (getting back to that later).// Add Aspire service defaults for exception handling, observability with open telemetrybuilder.AddServiceDefaults();To add Redis we only have to add one line of code. This will add a few things: Adding the StackExhange Redis connection multiplexer so that you can retrieve that with dependency injection in implementations. Look for the connection string to the “myRedisCache” connection setup in the orchestration. Setup specific Redis tracing, logging, and metrics.// Use the Aspire Components that make sure everything is added in the same way and open telemetry is addedbuilder.AddRedisClient("myRedisCache");If you look at the implementation you will notice that “AddRedisClient” is basically one big extension method that sets up everything for you in a certain opinionated way. The components do not include some sort of magic Aspire code. At least not in the components that I looked at. When in doubt you can always go to the components on GitHub to see the implementation.Tip: If you want to have custom tracing working with OpenTelemetry you have to add the tracing source. This will link your custom tracing to OpenTelemetry. Everything you trace with “MyActivitySource” will then be collected, sent, and shown in the Aspire dashboard.// Quick and dirty way to have the activity source availablepublic static readonly ActivitySource MyActivitySource = new("MyApi", "1.0.0");// Manually set the activity source name so that custom Activity tracing gets propagated to open telemetry.builder.Services.AddOpenTelemetry() .WithTracing(o => { o.AddSource(MyActivitySource.Name); });The same can be done with custom meters for metrics.What to do when your specific service is not available?Components are developed by Microsoft but also by the community. A good example of this is the development of Amazon AWS Components & Orchestration in this pull requestIf you can’t wait you always have the option to start a container like below with an AWS DynamoDb. It also shows how to get the endpoint which can be referenced like in the examples above. This way you can nearly start every docker image you want.var dynamoDbContainer = builder.AddContainer("dynamoDb", "amazon/dynamodb-local", "latest") .WithEndpoint(name: "dynamoDb", port: 8000, scheme: "http");var dynamoDbEndpoint = dynamoDbContainer.GetEndpoint("dynamoDb");Do not deploy itWhen explaining Aspire to other people I hear the same question a lot. How do I deploy this? Simply put, you dont. Just like you dont deploy your docker compose file. What is often meant is that they want the insights like tracing and metrics the default dashboard is giving. This I understand because it is helping you a lot in local development.For that reason they released the dashboard as an image for you to run anywhere if needed hereor use the docker standalone image:docker run --rm -it -p 18888:18888 -p 4317:18889 -d --name aspire-dashboard \ mcr.microsoft.com/dotnet/nightly/aspire-dashboard:8.0.0-preview.6Do note that there is no authenticaiton possible at the moment of writing this blog with preview 5.How to deploy it?Okay so I dont deploy the app host. But the other apps frontend, myApi, and Redis cache should be deployed. When you do deploy your application with your favorite CI/CD pipelines or any other means there is one thing you should configure. Since your orchestration is not deployed you have to link the parts of your application together. Basically like your used to.Let me give you a schematic overview of how it all links together.Local DevelopmentProduction environmentAs you can see only the left part is replaced. This is done through environment variables. Do note that this is the part of the opinionated part but as of preview 6 this can be changed if it adapts better to your existing project. For more info see this doc. Let’s continue on how the default way is set up.For the dotnet MyApi project, you can configure it like this:"ConnectionStrings": { "myRedisCache": "your-redis.url:6379"}If for some reason you want to link 2 API services together the config in the environment will look like this"services": { "myApi2": { "http": "your-api.url" }}In the frontend you can again use the environment variables in the env.production or any env file you have.MY_API_ENDPOINT=$services__myApi__http__0/api/v2.0/my/callAll in all, will Aspire help you to get up and running for local development with a distributed application. I am already seeing the benefits of using it when there are 2 or more components. We will have to see how this all develops in the future. For now, at least Aspire looks very promising to me.This concludes this blog post. I suggest you give Aspire a try and see for yourself how remarkably easy it is to set up and use. Let me know what you think of this opinionated framework in the comments! --- # How to use middleware with Azure Functions URL: https://www.re-mark-able.net/blogs/2021/05/09/azure-functions-middleware.html Published: 2021-05-09 Tags: Azure, Azure Functions, Middleware, .NET 5 Lately, I was hearing more and more about middleware with DotNet Core and now again with the release of .NET 5 in combination with Azure functions. As it turns out it is only a few steps to create a middleware for an Azure Function.If you want to add a middleware to Azure functions, all you have to do is register it in your HostBuilder and create a new class that inherits from IFunctionsWorkerMiddleware.Let’s take a look at what middleware is, why you should use it, and how we get it up and running in .NET 5.What is middlewareMiddleware is a piece of code that sits before and after the execution of your function in a so-called pipeline. The image below will demonstrate this. The initial request arrives at your function app and then travels through all the middlewares until it reaches your function. It is important to note that the middlewares are executed in the order they are registered.Each middleware has a “before” and “after” part. Everything before the “next()” is executed before your function is executed. Likewise everything after the “next()” will be executed after the execution of your function.The use of middleware will allow you to react to incoming requests but also to change the outgoing response before they leave your function app. Let’s take a look at the possibilities and what you can use this for.Why and when to use middlewareThere are certain situations where you are repeatedly copying the same code. For example, when you build Azure Functions as an external API you don’t want to expose any information about the inner workings in a response. This happens when a exception is thrown and you don’t catch it. Therefore you need to wrap everything in a try-catch and handle the exceptions. Of course, you can make a fancy wrapper for that but you would still be copying the wrapper everywhere. With middleware, you can wrap the “next()” method in a try-catch and handle it in one place.Other use cases for middleware are: Authentication Performance and tracing monitoring Logging Encrypt/Decrypt incoming requests and outgoing responses Custom CachingThe considerations of using middlewareWhen using multiple middlewares it can become very confusing when and in what order everything is executed. That’s why I would recommend, that in the program.cs where your HostBuilder is, you document why one middleware should execute before the other.The other downside is that the middleware is executed on every incoming call for the entire function app. Every middleware needs to decide on its own if it is applicable for this incoming request. So quick if this then that checks are great to do but if you are going to query a database for information keep an eye on the performance.The last con is that middleware in combination with Azure Functions does not have the ability to change the outgoing response or terminate the pipeline.. yet… There is an open issue at the time of writing here. As stated in the issue it will come but it will probably take some time. For now, let’s create a middleware for Azure Functions in .NET 5 and see what we can do.How to use middleware with Azure FunctionsFirst, we have to create a middleware class. Let’s call it “ExceptionLoggingMiddleware”. The main responsibility for this middleware is to log every exception that is occurring within the function app as a warning. It does not matter where you create the class as long as it is in your Function App project.Now that we have a middleware class we still need to make it a middleware. We do this by inheriting from the IFunctionsWorkerMiddleware interface and implementing the interface. Your code should be like this:public class ExceptionLoggingMiddleware : IFunctionsWorkerMiddleware{ public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next) { await next(context); }}Now, let’s give this middleware some code so that it actually does something. We are going to add a try-catch and get a logger instance from the provided context by Azure Functions runtime.public class ExceptionLoggingMiddleware : IFunctionsWorkerMiddleware{ public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next) { try { // Code before function execution here await next(context); // Code after function execution here } catch (Exception ex) { var log = context.GetLogger<ExceptionLoggingMiddleware>(); log.LogWarning(ex, string.Empty); } }}This should be enough to log every exception as a warning. If we run the function project you will see that the middleware is not called. This is because we didn’t register it yet in the program.cs where you initialize your host builder. Program.cs is the default startup class but it can be named differently in your project. The best is to search for where “HostBuilder” is used.public class Program{ static Task Main() { var host = new HostBuilder() .ConfigureFunctionsWorkerDefaults( builder => { builder.UseMiddleware<ExceptionLoggingMiddleware>(); } ) .Build(); return host.RunAsync(); }}So now when we call a function that has the code provided below you will see that it logs the warning to your console window and if you have Application Insights configured it will be logged to there.[Function("MyFunction")]public async Task<HttpResponseData> MyFunction([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "myfunction")] HttpRequestData req){ throw new Exception("Ooops");}This is all for now, if you have any questions feel free to post a message in the discussion on GitHub here. Thanks for reading! --- # How to add C# to Azure API Management Policies URL: https://www.re-mark-able.net/blogs/2021/05/02/csharp-policies-apimanagement.html Published: 2021-05-02 Tags: Azure, API, Policies, Azure API Management Using Azure API management has some great advantages like not having to manage your own proxy to aggregate all your API’s or microservices into one endpoint. If you have used Azure API management before then you know there is an option to edit policies to change the incoming or outgoing requests.What are policies?With policies, you have full control over how your API calls travel through your API management to the backend. You can set policies on one specific API call or the entire API. Adding a policy is mainly done in XML but before we go there, here are some examples of what you can do: Access restrictions to block IP addresses, limit call rate and validate JWT tokens Advance policies to mock responses (for testing) and retries Caching policies to store and retrieve data from a cache Transformations for JSON to XML or vice versaIf you want extended information please take a look here.Adding a policyNow that we know a little about what policies can do, let’s add a new policy to an Azure API management instance. I am going to assume you already have an API created or like me using the default echo API. Go to that API and click on a specific API call. You will see something similar to this:Now click on </> in the “Inbound processing” to enter the policy window. Here you can add all the different types of policies like only allowing a certain IP address range like this:This specific call will be limited to only allow a specific range of IP addresses. The same can be done for a rate limit policy which can be used to protect a backend service from receiving too many requests. For other policies, you can also go to the snippet window in the top right corner to select a policyAdding C# to a policyWe now know what policies are and what they can do but what about more advanced scenarios? What if I have an API that is receiving documents with metadata in JSON format and I only want to save the document in blob storage and not the metadata. This is because the metadata is handled by a different backend than the document processing.{ "fileName" : "filename.ext", "meta": "more meta data here", "doc": "base64string of the document"}The JSON is pretty basic with some metadata properties. We now only want to select the property “doc” which contains the document. This can be done by using C# in the policy and a total overview of the policy is also provided later. First, we need to extract the incoming body from the request and save it to a variable and also save a random filename so that the blob can be saved.<set-variable name="body" value="@((string)context.Request.Body.As<string>(preserveContent: true))" /><set-variable name="fileGuid" value="@(Guid.NewGuid().ToString())" />As you can see in the value property which begins with ‘@(‘ you can write plain C# after that. If you want multi-line you can use “@{}”. API management provides some default variables like “context” which contains the body of the incoming request. After that, you can access the rest of the body and save it as variables.Next, we need to start creating a send-request to blob storage and that can be done like below where we also concatenate a string that represents the URL of where the blob will be saved. In that URL, we are again using C#. Also, notice the headers that we are setting here to generate a valid request to an Azure storage account.<send-request mode="new" timeout="300" response-variable-name="blobdata" ignore-error="false"> <set-url>@("https://myblobstorage.blob.core.windows.net/yourdocscontainer/" + context.Variables.GetValueOrDefault<string>("fileGuid"))</set-url> <set-method>PUT</set-method> <set-header name="x-ms-version" exists-action="override"> <value>2019-07-07</value> </set-header> <set-header name="x-ms-blob-type" exists-action="override"> <value>BlockBlob</value> </set-header> <set-body> <!-- See below --> </set-body> <authentication-managed-identity resource="https://storage.azure.com" /></send-request>The last thing we need to do is setting the body of the request to an array of bytes that can be saved to blob storage. Retrieving the “doc” property from the incoming request and converting the base64 string to bytes can be done like this<set-body> @{ var body = (string)context.Variables.GetValueOrDefault<string>("body"); var jsonObject = JObject.Parse(body); var base64String = (string)jsonObject["doc"] ; var bytes = Convert.FromBase64String(base64String); return bytes; }</set-body>No this is not the cleanest or shortest code but I wanted to keep it as simple and readable as possible and not putting everything in a single line. Below is the full policy that contains all the parts until now.<policies> <inbound> <set-variable name="body" value="@((string)context.Request.Body.As<string>(preserveContent: true))" /> <set-variable name="fileGuid" value="@(Guid.NewGuid().ToString())" /> <send-request mode="new" timeout="300" response-variable-name="blobdata" ignore-error="false"> <set-url>@("https://myblobstorage.blob.core.windows.net/yourdocscontainer/" + context.Variables.GetValueOrDefault<string>("fileGuid"))</set-url> <set-method>PUT</set-method> <set-header name="x-ms-version" exists-action="override"> <value>2019-07-07</value> </set-header> <set-header name="x-ms-blob-type" exists-action="override"> <value>BlockBlob</value> </set-header> <set-body> @{ var body = (string)context.Variables.GetValueOrDefault<string>("body"); var jsonObject = JObject.Parse(body); var base64String = (string)jsonObject["doc"] ; var bytes = Convert.FromBase64String(base64String); return bytes; } </set-body> <authentication-managed-identity resource="https://storage.azure.com" /> </send-request> <choose> <!-- Return an error to the caller of the api when storing in blob is failed --> <when condition="@(((IResponse)context.Variables.GetValueOrDefault<IResponse>("blobdata")).StatusCode != 201)"> <return-response> <set-status code="400" reason="@(((IResponse)context.Variables.GetValueOrDefault<IResponse>("blobdata")).StatusReason)" /> <set-header name="ErrorReason" exists-action="override"> <value>@(((IResponse)context.Variables.GetValueOrDefault<IResponse>("blobdata")).StatusReason)</value> </set-header> </return-response> </when> </choose> <!-- Add your backend call here if you only want it to be called on a successful storage call--> <base /> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error></policies>With this, we completed including C# into Azure API management policies. This is all for now, if you have any questions feel free to post a message in the discussion on GitHub here. Thanks for reading! --- # Azure on a budget, forecasting your spending URL: https://www.re-mark-able.net/blogs/2021/04/25/azure-on-a-budget.html Published: 2021-04-25 Tags: Azure, Cost, Budgets When developing software and deploying it to Microsoft Azure you will most likely encounter some form of cost management. Also questions on: What is this going to cost me or how much is this every month? Let’s look into Azure Cost analysis and Budgets.Calculating your costFor every Azure resource, there is a pricing calculator, which you can find here. You can make calculations for the resource types you want. Let take for example the Application Gateway and assume there is a Products API that returns some product information in JSON. I am going to use the Application Gateway to access the API within a VNET. The usage with the current API is 1.000 users which generate 30.000 API calls per month. Let’s put that into the pricing calculatorProbably not the only one here but I have actually no clue how much Data processing or Outbound data transfer that is because it has never mattered before. Although the API is returning JSON there is some uncertainty. Since the costs are very low per GB I am taking the gamble and setting it up. Let’s see what the costs are after a week of usage.Cost analysisFor every resource group within Azure, you can get a Cost analysis. This also includes a forecast of the current month. You can find it by going to a resource group and scroll down in the left menu (like in the screenshot below). Here you will have an overview of the current cost (dark green) and the forecasting (light green).Now that you know where to find this cost is must state a small fact: This does not work for CSP subscriptions, these costs are hidden at the time of writing. As you can see in the previous image there was already a Budget set on this resource group. The last thing I want to do with my time is to look at the cost of Azure all day.BudgetsIn the same menu on the left, you will find budgets. Budgets lets you set an alert on a resource group or a specific resource within that group. This allows you to react to overspending or even when the forecast is indicating that you will exceed your budget at the end of the month.By creating a budget you can set your desired budget details like the renewal period and the budget amount. Just as important is the budget scoping. Here you can set filters on what resources you want to be included in the budget. By default, it will take the entire resource group. When you just created the resource group and the resources the forecast will be empty for a few hours.You can set the alert conditions to the actual cost or the forecasted cost.After setting your alert conditions you have the option to set an action group. These are the same action groups you can set on Azure alerts and alerts on Log Analytics. Within an account group, you can also trigger Azure Logic apps for example. This enables you to alter your resources when certain budgets are exceeding the limits.Nou that we have saved everything the Azure portal will also show you the progress of that budget.This is all for now, if you have any questions feel free to post a message in the discussion on GitHub here. Thanks for reading! --- # Security headers with Azure static websites URL: https://www.re-mark-able.net/blogs/2021/04/18/security-headers-with-static-sites.html Published: 2021-04-18 Tags: Azure, Static Website, Verizon CDN When creating a static website by using a storage account (not the new Azure Static WebApp) you have no say about what security headers are sent to the end-users. This can be easily solved by using a premium CDN like Verizon. First, let’s explain a little about what security headers are and why you should care.Security headers?According to OWASP, you should not divulge any information about the server or its configuration to the end-user as this can be used by hackers to exploit a vulnerability. But what are security headers?Security headers are sent between the server and the client for every request that is made, like loading HTML, images, or API calls. These headers indicate if some options are possible in the client and are sent in a simple form of key and value. Let’s take an easy one like ‘X-Frame-Options: Deny’. If this header is present it prevents the current page from being loaded into an iframe on another page or website.If you want to look at the security headers yourself you can open de developers tools of your browser (F12 for Edge) and go to the network tab. Then browse to https://www.google.com and your result will look like the screenshot below. As you can see, Google only allows this specific resource to be in an iframe of the origin is the same as google.com.If you want to do this with Azure Static website by using a storage account then you are out of luck. There is no option to enable or change the headers. Instead, let’s see what a Premium Verizon CDN brings us. Ouch sounds expensive…Setup Premium CDNWithin a storage account, you have the option to configure a Azure CDN (in the menu). A CDN is designed to deliver static content like images, audio, and video faster to the end-user because it will locate the nearest datacenter and retrieve the file from there. You can create a Verzion CDN like thisMake sure to select the Static website and not the blob container. When this is done you will have multiple new resources in your resource group. You will have a new CDN Profile and an Endpoint resource. If you look closely you will see that these resources are created a global location and not a specific region. Now, let’s look into the created ‘CDN Profile’ resource which will be your Verizon CDN.It can take some time to get it into a running state. In the top right corner, you can see that this is a Premium Verizon CDN. You can access the Verizon page by clicking ‘Manage’ at the top. For me, the authentication didn’t work flawlessly in the beginning. Looks like Verizon needs time to set everything up on their side, so give it some time.To be able to add security headers we need to go to the Rule Engine. This can be done by opening the HTTP Large menuWhen you open the rules engine there is an option to create a draft rule. Rules in this rules engine go through multiple stages: Draft > Staging > Production. When in production they are live and actively used.The rules engine is very easy and will allow you to manage all your headers. Using the action ‘Overwrite’ will allow you to update and if they do not exists add the headers like X-Frame-Options. If you want to remove the headers of Microsoft then you can also do that with the ‘Delete’ action as seen below.If you save these changes and push it to production you can browse to your static website and see that the headers are applied. This is all good, but what does it cost? I mean it’s a Premium Verizon CDN.What does it cost?With a Verizon CDN, you do not pay per transaction. You pay for the data transferred and there are no upfront costs. In this example, we calculate with a high traffic website that has transferred 50GB of data on static files.As you can see it’s only ~$14 a month for this solution. The other options are using a Azure Frontdoor or an Application Gateway which are both much much more expensive.This is all for now, if you have any questions feel free to post a message in the discussion on GitHub here. Thanks for reading! --- # How to do multi-trigger Azure Logic Apps URL: https://www.re-mark-able.net/blogs/2021/04/11/logic-app-multi-trigger.html Published: 2021-04-11 Tags: Azure, Logic Apps When developing solutions with Azure Logic Apps you often run into limitations in comparison to developing with C# & .NET. But it is also much much simpler to connect business applications with the few hundred connectors available today. One of the limitations is that the designer does not support multiple start triggers at this time. However multiple start trigger is possible. Let’s see how we can do this.Creating a logic appStart by creating a new Logic App and added the step “When a HTTP request is received”. You can save the logic app and it will create a URL where you can post data to.When we see the code view behind this logic app it will be similar to the one below. We can now post to the URL the designer view is giving you.{ "definition": { "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", "actions": {}, "contentVersion": "1.0.0.0", "outputs": {}, "parameters": {}, "triggers": { "manual": { "inputs": {}, "kind": "Http", "type": "Request" } } }, "parameters": {}}Adding the second triggerNow we can add a second trigger but before we do that there is one nasty caveat with this approach.. You will lose the designer view. Even when this is the case it still can be useful in advanced scenarios where you can not create resources yourself in Azure due to company policies (and it took you 3 weeks to create this above logic app.. it happens). Or maybe you just want multiple recurrence triggers. On the latter, let’s add a recurrence trigger as the second trigger.{ "definition": { "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", "actions": {}, "contentVersion": "1.0.0.0", "outputs": {}, "parameters": {}, "triggers": { "Recurrence": { "recurrence": { "frequency": "Minute", "interval": 1 }, "type": "Recurrence" }, "manual": { "inputs": {}, "kind": "Http", "type": "Request" } } }, "parameters": {}}As you can see the property ‘triggers’ is already plural and should support multiple triggers. By adding the recurrence trigger you can have multiple triggers. As documented in the Microsoft docs here, you can have up to 10 triggers.DownsideNow that we have 2 triggers the Logic App will fire when called by an HTTP request but also every minute. As stated earlier the downside is that you cannot use the designer anymore. Not for the run history and not for updating the Logic App.Should you use this?TLDR: No. This should only be used when you have no other option since the designer and run history views are what is making Logic Apps great. Since creating Logic Apps does not bring any extra costs you should just create multiple Logic Apps. Each of them with the specific trigger you want. Then all Logic Apps with the triggers call the one logic that will execute the trigger.TIP: Pay attention to the ‘Retry policy’ setting when calling other Logic Apps. It can cause some unwanted retries.This is all for now, if you have any questions feel free to post a message in the discussion on GitHub here. Thanks for reading! --- # Blazor WebAssembly with Azure Active Directory and Functions URL: https://www.re-mark-able.net/blazor-webassembly-with-azure-active-directory/ Published: 2020-04-02 Tags: Blazor, Serverless Since the newest Blazor WebAssembly version we have to possibility to use MSAL to authenticate with Azure AD and other OpenID Connect providers. In this post I will focus on authentication with Azure AD. For this I created a repository on github.This solution will allow you to authenticate and make calls to an Azure function with Blazor WebAssembly.The Azure function and Blazor app will be Azure Active Directory protected.Prerequisites Use the latest Blazor preview installed 3.2.0-preview3.20168.3. See here for more info.Getting StartedFirst, we need to create an app registration in your Azure Active Directory. You can do this by going to https://portal.azure.com for the Tenant you want to deploy your app in. Create an application like below. Set the redirect URL to localhost so that you can use it on your local machine.After your registration is completed it should look like this:Go to the “Expose Api” page and set the Application ID URI to API://clientid. My client id in this case is ddc79846-0ed0-4347-a997-dc10bcf58e48. After this, you also need to set the scope. Set this to API://clientid/user_impersonation and Save.Now, let’s go to the Authentication page and change the URLs to match the ones below. Als make sure to check the Access Tokens and ID tokens checkbox. If you haven’t already done so make the app multi-tenant at the bottom.Azure function configI am not going in-depth on how to deploy an Azure function and will go straight to the configuration. Before we do that we need to take 2 things from the application registration we just configured Client ID Client Secret (Generate one in the Certificates & Secrets page)After you have copied these go to your azure function and go to the new still in preview portal of Azure functions. Go to the Authentication/Authorization page.Do 3 things here: Switch App Service Authentication to On Set Action to take when a request is not authenticated to Log in with Azure Active Directory Click the Azure Active Directory rowThe second to last step is to set the Active Directory Authentication to advanced and paste you two values we copied earlier.This should be enough to get it working. Still, if you want to make sure it works on your local machine we have one more setting to go.Go to the cors page of azure functions and set an extra cors rule to your localhost environment as I did:Configure the SolutionFor you to be able to run this solution there are a few settings that need to be done. Open the solution (or folder if you are in vs code) and edit the appsettings.json file in the Web project. Set your own clientId and API backend. This can be the Azure function we just configured or a localhost function. Do note that on your local machine you can not test the AD authentication.{ "clientId": "ddc79846-0ed0-4347-a997-dc10bcf58e48", "postLogoutUrl": "https://localhost:5001", "apiBackend": "https://<your azure functionn>.azurewebsites.net/api/" // or "https://localhost:7071/api"}That is it. If something is not working for you, feel free to create an issue on the github repository. --- # Azure AD Application Registration Security with Graph API URL: https://www.re-mark-able.net/azure-ad-application-registration-security/ Published: 2019-10-04 Tags: Azure, Active Directory, Graph Api In many Azure Active Directories, there are registered applications. These applications all have security permissions. Do you know which one has which permissions and can access what data and resources? Do you know who has the secrets that give access to this data? Let’s take a look at how we can achieve this.In this blog, I will show you how to generate a list of applications and the permissions they have by using the beta version of the Microsoft Graph API. This will allow you to act on them. It is fine if some applications have a high permission level. At least after reading this blog you have the change retrieve them and to make sure the owners of the applications guard the secrets the best they can. Let’s dive right into retrieving the applications.Don’t know what Azure Active Directory Application registrations are? Check out this earlier blog post. If you wanna know more about the Microsoft Graph API beta you can see this blog on how to connect to it.Setup app registration with permissionsBefore we can retrieve the applications from the Graph API, we need to authenticate it to the Azure Active Directory. This is done by adding an application registration. Yes, this is the same type of application we are trying to retrieve. In this case we are need to create a application registration with Directory.Read.All permission.To create an application you can go to my GitHub here. There is a detailed guide in the readme on how to set this up. After you are done retrieving the applications, make sure to disable or delete this application.Now that you have created the application, you can get an access token. We do this in C# by using the MSAL library (Microsoft.Identity.Client). This allows you to generate the token we use later in this blog.var ccab = ConfidentialClientApplicationBuilder .Create(clientId) .WithClientSecret(clientSecret) .WithTenantId(tenantId) .Build();var tokenResult = ccab.AcquireTokenForClient(new List<string> { "https://graph.microsoft.com/.default" });var token = await tokenResult.ExecuteAsync();return token.AccessToken;The token we just retrieved is a JWT token that permits us to access the Graph API. Specifically in this case to retrieve the applications from an Azure tenant. If you ever wonder what permissions are associated with the current token. Go to https://jwt.io/ and paste in your token.Retrieve ApplicationsTo retrieve the applications we use the previous access token and make a GET call to https://graph.microsoft.com/beta/applications. Notice that we make use of the beta version of the Graph API.Below is the C# code:using (var request = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/beta/applications")){ request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "<Your Access Token Here>"); using (var client = new HttpClient()) using (var response = await client.SendAsync(request)) { response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); }}Executing this code will return all the applications from the tenant. Each call to the Graph API will result in a maximum of 100 results. If there are more results, there will be a nextlink property with a URL to retrieve the next 100 results.Below is an example of the JSON returned. I removed a lot of empty properties in this case. As you can see we have retrieved an application but the only readable data is the display name. What API’s is this app giving permissions to? What permissions are assigned? Are these delegated or application permissions?{ "id": "1deb4abb-fea2-401b-8881-0bf7f86dda12", "appId": "092424f2-09ba-49fb-bfd1-f4fd9c352e82", "createdDateTime": "2019-08-10T21:08:51Z", "displayName": "Data Engine", "appRoles": [], "keyCredentials": [], "passwordCredentials": [], "requiredResourceAccess": [ { "resourceAppId": "00000003-0000-0000-c000-000000000000", "resourceAccess": [ { "id": "465a38f9-76ea-45b9-9f34-9e8b0d4b0b42", "type": "Scope" }, { "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", "type": "Scope" }, { "id": "df021288-bdef-4463-88db-98f22de89214", "type": "Role" } ] } ]}To make sense of al these guids we need to retrieve some extra data. By retrieving the service principle of each API we can link the guids to some actual text.Retrieve service principlesFirst, let’s retrieve the service principles in the Azure tenant. We are doing the same call as before with a slight difference in the URL. Instead of calling the /application we now call /servicePrincipals?filter=appId eq ‘00000003-0000-0000-c000-000000000000’. This will retrieve the associated API.using (var request = new HttpRequestMessage(HttpMethod.Get, "/servicePrincipals?filter=appId eq '00000003-0000-0000-c000-000000000000'")){ request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken); using (var client = new HttpClient()) using (var response = await client.SendAsync(request)) { response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); }}As you can see below it will return the information about the Microsoft Graph. Also for this response, I deleted a lot of properties to make it a little more readable.{ "id": "9a1be802-1792-48de-92e4-ea67cb2ec6e9", "appDisplayName": "Microsoft Graph", "appId": "00000003-0000-0000-c000-000000000000", "displayName": "Microsoft Graph", "publishedPermissionScopes": [ { "adminConsentDescription": "Allows the app to read events in user calendars . ", "adminConsentDisplayName": "Read user calendars ", "id": "465a38f9-76ea-45b9-9f34-9e8b0d4b0b42", "isEnabled": true, "type": "User", "userConsentDescription": "Allows the app to read events in your calendars. ", "userConsentDisplayName": "Read your calendars ", "value": "Calendars.Read" }, { "adminConsentDescription": "Allows users to sign-in to the app, and allows the app to read the profile of signed-in users. It also allows the app to read basic company information of signed-in users.", "adminConsentDisplayName": "Sign in and read user profile", "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", "isEnabled": true, "type": "User", "userConsentDescription": "Allows you to sign in to the app with your organizational account and let the app read your profile. It also allows the app to read basic company information.", "userConsentDisplayName": "Sign you in and read your profile", "value": "User.Read" } ], "publisherName": "Microsoft Services", "appRoles": [ { "allowedMemberTypes": [ "Application" ], "description": "Allows the app to read user profiles without a signed in user.", "displayName": "Read all users' full profiles", "id": "df021288-bdef-4463-88db-98f22de89214", "isEnabled": true, "origin": "Application", "value": "User.Read.All" } ]}In the JSON result above you can also see that there are published permission scopes and approles. published permissions scopes are your delegated permissions and the approles are your application permissions. As you can see there is a lot of human-readable text instead of guids. Below is a simple overview of how each property links to another.Now that we have retrieved the application we also want to know who the owner is. In case we have questions or for governance purposes, you want to know who owns the applications.Retrieve the ownersRetrieving the owners is again the same principle as the other calls. By supplying your app id in the URL you can retrieve the owners of that specific app. It can return multiple results.using (var request = new HttpRequestMessage(HttpMethod.Get, $"/applications/{AppId}/owners")){ request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken); using (var client = new HttpClient()) using (var response = await client.SendAsync(request)) { response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); }}When the call is executed you will receive a JSON response similar to this{ "@odata.type": "#microsoft.graph.user", "displayName": "Mark Foppen", "jobTitle": "Developer", "userPrincipalName": "test@re-mark-able.net"}Output wrapped in web applicationNow you know how to retrieve the applications from you Azure tenant, link all the properties together and retrieve the owners, it is time to make it a little more visible then JSON output. To do this I created a simple web app that shows the output of the call for your specific tenant. The source code can be downloaded from my GitHub hereMaking it more secureNow we know what applications we have and what permissions are assigned. We also retrieved who the owner is. Now it’s up to you to at least retrieve all the applications from your tenant and put some sort of governance on them. Of course, it is okay to keep applications that have permission to access data but now you can at least compare en react on it. Contact the owners to check if the app is still used and discuss why those permissions are needed.Thanks for reading and keep pushing to make things more secure! --- # Sending your Threat Indicators to Azure Sentinel URL: https://www.re-mark-able.net/adding-threat-indicators-to-sentinel/ Published: 2019-08-18 Tags: Windows Defender for Endpoint, MDATP, Sentinel How and why should you send your threat indicators to Azure Sentinel or add them manually to the Microsoft Defender Advanced Threat Protection (MDATP) solution? What is an indicator, also known as an Indicator of Compromise (IoC)? Why should you care? How can you do this? Let’s go through this and add indicators manually and by using a Logic App and the Microsoft Graph Security API.First, we will take a look into what an Indicator is and how it works in MDATP to get a better understanding of what we are dealing with. Then send the indicator to Azure Sentinel through the Microsoft Graph Security API.What is an indicator?An IoC is a piece of evidence that could indicate you have malicious activity in your environment. This can have many forms i.e.: File hashes Network activities Ip address or URL’sThe IoC on its own doesn’t necessarily mean you have been compromised. Often the combination of file hashes, network activity, and origin (IP or Url) are the providers of context which in turn determines if it is a threat. For more info, you can have a look at the Mitre ATT&CK framework here. This is a framework to describe what tactics and techniques are used to identify and defend against attacks on your organization.This is all good and fine but what if you encounter an application on one of your managed devices and want to block it for the entire organization? Take for example an Android application (.apk) that is not detected by MDATP at the moment. As we all know these applications can also have malware in them or download other applications. One of your users sends it to another and another and so forth. How can you stop this? By adding the file hash of the APK to the indicators in MDATP. This will stop the spreading of the file and allow you to further investigate it.Add an indicator manuallyLet’s go to the MDATP portal and sign in. To get to the Indicators page we first have to go to Settings in the left menu and then to the indicators page. Here you have an overview of all your indicators. This should look like the portal belowBy clicking on +Add Indicator we can add a new indicator manually. Here you must give the file hash which can be a SHA1, SHA256 or MD5. For now, there is a limit of 5000 indicators at the time of writing this post. By setting the expiration date you automatically clean them up.When you go to the next step in adding an indicator you must determine the actions MDATP should take when there is a file with the same hash. We have 3 possible actions: Allow Alert Only Alert and BlockAllow is used when MDATP is already blocking a file or executable that you do not want to be blocked. Take for example Mimikatz, if you put the file hash of that in here you can use the program without MDATP putting it in quarantine.Alert Only is used when you only want to receive an alert that the file is detected but not want to block it. If you can post the Alert yourself you should not be using this. Instead use the MDATP API (docs here) to create the alert. This way you won’t be using another spot on that 5000 entries limit.Alert & Block is used when you immediately want to block the file on all or scope of machines. Be very careful with this option. If a critical windows file ends up here it will have an impact on your organization.The 3rd and last page is to set the scope of the indicator. In the screenshot below you don’t see any scope since I don’t have any. The scope can be set to a determined list of machines or all machines in the organization.The last step is the summary to make sure you didn’t make a mistake and double-check your input.After we completed these simple steps you will see the indicator added to the list.Add Indicators through the Microsoft Graph Security APINow that we have a good understanding of what threat indicators are and how they are working, we can start adding them to Azure Sentinel. Why would we want to add them to Azure Sentinel? Azure Sentinel is a very good product to correlate security events across different log sources and different Microsoft security products. Make sure that the Threat Intelligence data connector in Azure Sentinel is enabled.To add the indicators to Azure we are using the Microsoft Graph Security API (beta). Before we post a new indicator we need to set some properties first: Action: Alert, only give an alert, do not block the file. FileHashType: SHA256, in this example we only process SHA256 hashes to keep it simple FileHashValue: The actual file hash ExpirationDate: When will the indicator expireA basic post message would look something like this:{ "action": "alert", "activityGroupNames": [], "confidence": 0, "description": "This is a canary indicator for demo purpose. Take no action on any observables set in this indicator.", "expirationDateTime": "2019-03-01T21:44:03.1668987+00:00", "externalId": "Test--8586509942423126760MS164-0", "fileHashType": "sha256", "fileHashValue": "b555c45c5b1b01304217e72118d6ca1b14b7013644a078273cea27bbdc1cf9d5", "killChain": [], "malwareFamilyNames": [], "severity": 3, "tags": [], "targetProduct": "Azure Sentinel", "threatType": "WatchList", "tlpLevel": "green",}To keep it simple you can either post this to the Graph Security API with postman or by using an Azure Logic App as I did. Your Logic App Http step will look similar to below:In the logic app, you see a client id and client secret. These are from the application registration and you can have a look here how you can set that up. Keep in mind that your application needs the permission ThreatIndicators.ReadWrite.OwnedBy for the request to work. This permission needs to be granted by a global administrator in your tenant. Did you notice the targetProduct property set to Azure Sentinel? This is what specifies where the indicator is redirected to.After a successful post, you can view the indicator in the Azure Sentinel dashboard. This can be done by going to the ThreatIntelligenceIndicator log sourceWhen you query this you will get something similar like below, depending on how many indicators you posted.It is re[mark]able how easy it is to add indicators to MDATP and Azure Sentinel, but yet so powerful. Now you can leverage the data of indicators in Azure Sentinel alerting, correlation and hunting.Thanks for reading! --- # Understanding Azure Active Directory App Registrations URL: https://www.re-mark-able.net/understanding-azure-active-directory-application-registrations/ Published: 2019-08-14 Tags: Azure, Active Directory Why should you care about Azure Active Directory (AAD) Application Registrations as a global administrator or any other role that can approve them in your organization? In many Azure Active Directories (AAD) there are registered applications. These applications could all have security permissions and maybe even admin consents to access data across your organization. Do you know which one has which permissions and can access what data and resources? Do you know who has the client secrets that give access to this data? Let’s take a look at a non-technical approach to AAD Application Registrations.What is an Application RegistrationThe application registration in your tenant enables you and others to authenticate against your Azure Active Directory. Another option is to authentication through an application secret. A default application registration on its own cannot do much more than validating that the user has valid login credentials. This can be your Active Directory or in case of a multi-tenant application the directory where the user is originated from. It is also possible to let users login with their @outlook.com and @live.com accounts if you configure this.If you go to your AAD in the Azure portal you can view all the registered applications in your tenant.So what other benefits would an application registration have? First, let’s think of a scenario where we would need one. Scenario: The customer wants a single web page where users sign-in with their AD account and view their profile information. This is done by using the Microsoft Graph API to retrieve the profile data.The developers of the application implement the requirements and when they start testing it is failing on retrieving the information from the Microsoft Graph API. Something similar to this is what they will see:In the application registration, you have the option to specify which permissions the application has. Each permission gives access to a part of your resources or users within your Azure tenant. For this scenario the permission User.Read would be enough to read basic profile information. What other kinds of permissions can we expect? We will talk about that in a moment.If you want to see how you can configure a new application registration in your tenant then you can have a look at my previous blog here (technical) on how to register a new application. Of course for extended details, you can always take a look at the official Microsoft documentation here.Different Types of PermissionsThere are hundreds of permissions you can give an application. You first need to choose which API and then select the permissions you want. To give an impression:As you may have seen there are 2 types of permissions you can choose: Delegated ApplicationDelegated permissions are used when you want to authenticate to an API or other services with the currently logged-on user. This typically involves a physical user and a user interface. A delegated permission will never give the user more permissions then they already have within this AD.If an application registration has the permission Directory.ReadWrite.All and a normal user without any privileged roles logged in into the application. The user will not be able to write to the current directory. When for example a Global Administrator logs in, he will have the ability to write to the directory.Application permission are used when there is no user present. Mostly used for API to another API calls. This is also used for background services. Unlike delegated permissions, application permissions, however, uses the app id and secret to login and always has the given permissions of the application. Application permissions (almost) always require admin consent since it can give users more permission then their account.Be very careful what permissions are given to an app registration that uses Application permissions. There is literally only one secret needed to access the application because the app id is often publicly known. Since there is no Multi-Factor Authentication (MFA) available, because this authentication is based on no user interaction, generate the secrets with an expiry time or rotate them on a scheduled basis. This is however not supported by the Azure Portal at the moment. In my opinion, this should be taken into consideration when the application is designed.Before an application can be used with any privileged permissions there is, as stated above, an admin consent required. Let’s find out what consent is and what types are available.Giving ConsentWhat are the types of consent that can be given? There are three at the moment. User consent, admin consent and admin consent across the entire organization. The last two can, as the name indicates, only be given by a Global Administrator of that tenant.User Consent User authorizes that their data can be used (image) Limited to only permissions that the user can consent to The Graph API i.e. published a list of all the permissions with an indicator if admin consent is required. You can find the list hereAdmin Consent Can only be given by a Global Administrator Often for permissions that can make alterations to other objects than the current user When admin consent is needed, your users will get a message like this:Admin Consent on behalf of Organization Give consent for the entire tenant Users do not get a permission consent screen anymore Users don’t see which data is used from them CAUTION if you consent here, you give the entire organization permissions on this application.If you don’t want everyone in the organization to have access to this app you can block that by setting User assignment is required to Yes in the Enterprise application. More on this in the next part.This can also be done in the Azure portal by going to the application page in de AAD and clicking the Grant Admin Consent as you can see below Any user can add Admin permissions to their application registration although the permission are not active until granted by an actual Global Administrator.If you want to go more in-depth you can visit the docs at Microsoft hereManaging Enterprise ApplicationsWhen you create an application through application registration there is also an enterprise application created in your AAD once the first user has logged on. This is used to manage how the registration behaves in your organization. This could be in the same tenant as you created the application registration in. For a multi-tenant app, there would only exist an Enterprise Application. Enterprise applications can be found under your AAD in the Azure portalIn the enterprise application, you cannot change permissions, but you can manage your or an external (3rd party) application from here. This is what you can do: Enable or disable the ability for users to log in Change the Application icon User assignment is required - When turned to Yes user cannot log in into the application without first being added by the owner of the app or by some with a privileged role like a global admin. Visible to Users - Show or Hide the application in the office.com top left launcher menu (at the bottom). Delete the applicationIt will look something like thisWhy care about these applications?At the moment, if you don’t have a clear process for application registrations, it is very unclear what permissions are assigned to all the applications. But more importantly who has access. Over time an Azure tenant can have lots of applications. Most of them are harmless and just read the users profile to show a name or use the email address. But then some applications only use an application secret to get access.What happens when this secret gets committed to a git repository by accident. Sending this secret to other developers is also not a good idea. Although these examples shouldn’t happen that often, they do so be careful with this.On the other side, we always assume a security breach comes from external sources or mistakes from employees. What about internal breaches? How often does this happen? Take a look at a few sources: 75% are insider threats Even partners attack youWhat can happen?Any of the previous examples can result in a data breach or other malicious actions. Depending on what permissions the application has of course. In my opinion, for delegated permissions the chance of malicious action is very low, especially when MFA is enabled. For application type permissions this is a whole other world. When someone gets a hold of that secret they can do what the permissions allow them to.Possibilities: Read all your users Alter Azure resources Add and delete users etc, etc, almost anything you can do in the Azure portalThere is no way of linking it back to a user and it will not show up in any of the Microsofts Security products since it looks like a legit use of the application registration.Then there are is also something that is called an illicit consent grant. The attacker tricks the user into consenting an application on their website or by injecting malicious code into an existing website. This allows the hacker to access your data without you knowing. Microsoft already acknowledged this kind of attack and made a Detect and Remediation guide for it here.With all the things that could happen is it wise to check the application registrations in your tenant and act on them. Let’s see if we can get an overview of the application registrations in your tenantGetting the overviewNow we know what can happen, how can we get an overview of these applications? The Azure portal shows all the applications but it takes a lot of time to go into every application and check the permissions. This would be a major time sink. Unfortunately for the application type permissions, there is no other way at the moment. For delegated permissions there is a better way.What you can do is go the Microsoft Cloud App Security (MCAS) portal an see all the applications in your tenant with a permission level. This way you can focus on the high permissions applications first.In this portal, you can also see if there is a consent given for all the users in this organizationMaking it more secureNow that you have a basic understanding of Azure AD Application Registrations there are a few things you can do: Initiate an onboarding procedure for adding new Apps that have/need admin consent. Refresh secrets on a scheduled basis (custom implementation needed) Use Managed Identities where possible instead of connection strings Double check if the permissions are needed, i.e. don’t set Directory.ReadWrite.All application permissions when you just want to read AD groups. Use the specific Group.Read.All permission for this.We now know how to see what applications we have within a tenant and how to see what permissions they have assigned. What you can do now is up to you. Of course, it is totally legit to have all these applications with the permissions, but now you can at least set up a process to guide this. Contact the owners if the application is still used and why those permissions are needed.Although it still is re[mark]able how much effort it cost to get an overview of application type permissions. I will look into this for a next blog.Thanks for reading! --- # Using MDATP Streaming API with Misp URL: https://www.re-mark-able.net/using-mdatp-streaming-api-with-misp/ Published: 2019-07-23 Tags: MDATP, Threat Intelligence, Azure Would it not be great if you can access all the data from the new Microsoft Defender Advanced Threat Protection (MDATP)? It would be great if you can just access all that data through an API. But I really do not want to develop another polling mechanism to pull in all the data. That is where the new MDATP Streaming API comes in which just got enabled for public preview.In this post, you will see how easy it is to configure the new Streaming API and how you can get access to the data. You will see how the new API can be attached to Azure Storage and Azure Event Hub.Once we receive all the data we can check file hashes in a 3rd party threat intelligence provider like MISP. First, let’s configure the MDATP streaming API.Configure MDATP StreamingWe start by going to the MDATP portal here where you will see the default dashboard. To start configuring you need to go to the Data Export Settings page.In this page, you can add a total of 5 streaming connections. At the moment there are two types of Azure resources you can connect to: Azure Storage Event HubIf you choose for the Azure Storage option then the MDATP stream will save all the events in a *.json file as blobs.On each connection you can choose between 9 types of events: AlertEvents MachineInfo MachineNetworkInfo ProcessCreationEvents NetworkCommunicationEvents FileCreationEvents RegistryEvents LogonEvents ImageLoadEvents MiscEventsFor now, I am only going to focus on the connection between an Event Hub and MDATP for the FileCreationEvents. If you want to make sure that you catch all of the files and processes on every device you should also add the ProcessCreationEvents.When you add a new connection you will get all the options I just mentioned. You can make a choice here and configure the connection how you like. I am going to configure it for an event hub to only receive file creation events from MDATP.Now that the Event hub is configured the data should start coming in and it will look something like thisTip: Only enable the types of events you really want to have since the volume of messages can be very high. This is not an issue for Event Hub but could be very costly if you connect it to a logic app where you pay per execution.For example ‘NetworkCommunicationEvents’ logs every connection made on every machine. I had to learn the hard way by wasting my entire worth of monthly Azure credits ($150) in 2 days because it was connected to a Logic app :| …As you can see below most of the costs are in the connection and the executed actions for the logic app and not in the Event Hub. So be cautious as to what you connect to the Event Hub. The high event hub costs are due to the enabled ‘Capture’ feature and the standard tier. Not because of the number of events.This however triggered me to look into the actual costs of using the MDATP streaming API with Event Hub. To do that we first need to know how many events are sent. I created a new Event Hub namespace, connected it to MDATP streaming API and selected all available events. The next 24h I let it run to capture all the events. To give some context to this I have counted all the different types of events and the number of machines in my tenant.NetworkCommunicationEvents: 95,070ImageLoadEvents: 23,091MiscEvents: 57,444ProcessCreationEvents: 24,795RegistryEvents: 49,191MachineInfo: 2,213MachineNetworkInfo: 10,712FileCreationEvents: 39,487LogonEvents: 1,982AlertEvents: 4This leaves us with a total of 303.989 events on 83 different machines. The average size of one event is ~2.47 kilo byte and one machine gives ~3,662 events per day. On monthly costs, this would mean you have ~9 million events which will cost you around $0.25.Consuming Eventhub with a Logic appSometimes there are use cases that require a third-party threat intelligence system to check for malware. For example, to detect Android APK’s with malware in them. A good example you can see here. For this example, we will be using MISP also know as a Malware Information Sharing Platform and Threat Sharing. This is a free and community-driven threat intelligence platform. In this post, we will not cover how to set this up but you can see how this can be done on Kali Linux hereHere is a list of goals we want to achieve: Read the events from the event hub Check the file hashes against Misp Add the indicator to MDATPDo note that this is an implementation in the most basic form you can think off without any error handling or what so ever. Let’s take a look at the Logic App overviewFirst we receive the events through the Event Hub Logic App trigger which is connected to the MDATPStream hub as shown before. When you save the Logic App with only the trigger you will get a response like this:Now that we receive events we can call the Misp API with the following parameters to check if that file is known as a possible indicator of compromise (IoC).After this, we parse the response and check if there are any IoC’s returned from Misp. If that is the case we have found a match. At this point, it is up to you what you do with this detection. The first thing you could do i.e. is, Posting an Alert directly to MDATP with the Windows Defender Advanced Threat Protection (WDATP) logic app connector.The way to achieve alerting of the found IoC is through creating an alert with the WDATP connector. You can do this by adding it to your logic app and connect it with a global admin account.To create an alert, you need to set the machine id which can be found in the event hub message. For the other fields, you can set them as you like. To give meaning to the alert, you should call the Misp once again and retrieve the event from Misp. An event in Misp gives context to the found IoC and therefore also contains fields like title, severity, comments, etc.Possibilities?Although this post only describes one possible implementation of the MDATP streaming API there a lot more possibilities. To name a few: Save the MDATP data to a separate storage to retain it indefinitely Instead of polling your MDATP alerts from the graph API you can now respond to the alerts real-time Monitor network communication real-time Stream your data to a 3rd party that is handling your security Stream all the evens into your Security Information and Event Management (SIEM) solution Add your data to Azure Sentinel, since there is no connector yet.And a few others, just for fun or because you can Draw a world map and show all the unlock and logins in real-time by processing LogonEvents Respond to people that they shouldn’t work during their holidays by using the LogonEvents, ProcessCreation en FileCreationEvents ;)It is re[mark]able how much data is inside the MDATP product and for now we only scratched the surface. This should give you a good indication of what is possible in real-time with the MDATP streaming API.Thanks for reading! --- # How to access data from the beta channel of Graph API URL: https://www.re-mark-able.net/how-to-access-data-from-the-beta-channel-of-graph-api/ Published: 2019-07-08 Tags: Graph API, Azure All the new features of the Microsoft Graph API are first available in the beta version. By using the beta version you can get early access to new features. Microsoft often adds new features as can be seen on their GitHub changelog here.In this post we will do three things: Create an Azure Active Directory application registration Get the access token through the registered application Call the Graph API on the beta versionThis is all done by using the Azure portal and implementing the code to call the Graph API in C#.Adding an Application to your Azure Active DirectoryTo get access to the Graph API we need to register an application in the Azure Active Directory (AAD). This application can be used to add permissions. An administrator of that AAD can then consent to the permissions selected by you. Let’s go through this step by step.Open the Azure portal and go to the AAD that you want to add the application to. Now you can add the new application like thisWhen the application registration is created you can see 2 important id’s we need in a later stage. This is the Application (client) Id and the Directory (tenant) Id.Next step is to add permissions to the application registration. These permissions give the application the ability to access resources. In our case, this is the Graph API. Let’s add the Directory.Read.All which gives us permission to read everything within this AAD but not change it.As you might have seen there are 2 types of permissions: Delegated Permissions - These permissions are used when there is a signed-in user. Typically used for portals or Azure functions that have AD authentication. Application Permissions - Should only be used on background services. These permissions can only be granted by an administrator.Now that the application registration has the permission we want, it is still not granted. To grant this permission on this AD we need an administrator account to give consent. This can be done on the ‘API Permissions’ page where we just added the new permission.After giving consent to the permission there is only one thing left to do and that is adding a secret to the application. This is basically the same as a password that gives you access to use the application. Only in this case, you can have multiple secrets with each a different expiry time. You can also delete these secrets. To add a secret we need to go to the “Certificates & secret page”.Do keep in mind that you can only see the secret once. Now that we finished this we have the following data that we need to use in the next step:Tenant id: ‘5d1821a3-a004-4cc0-95d5-cb2e797ceaf1’App Id or Client Id: ‘42903c50-6fc9-40db-a131-87f4522dcf56’App Secret or Client Secret: ‘fe_?xg+VhSxe_iq4RSw9TE4AUlddktg8’We only created an app registration for a single tenant with default settings mostly. If you want more detailed information on i.e. a multi-tenant application you can go to the Microsoft docs here.Get the access tokenIn order to access the Graph API, we first need to acquire an access token. This token can be used as a bearer authorization header later on. To do this I used the NuGet package Microsoft.Identity.Client version 4.0.private async Task<string> GetAccessToken( string tenantId, string clientId, string clientSecret){ var builder = ConfidentialClientApplicationBuilder .Create(clientId) .WithClientSecret(clientSecret) .WithTenantId(tenantId) .WithRedirectUri("http://localhost/") .Build(); var acquiredTokenResult = builder.AcquireTokenForClient( // Here we set the scope to https://graph.microsoft.com/.default new List<string> { "https://graph.microsoft.com/.default" }); var tokenResult = await acquiredTokenResult.ExecuteAsync(); return tokenResult.AccessToken;}Call the Graph APINormally you would just use the Graph API client SDK which is the NuGet Microsoft.Graph but even the preview versions do not have all the available calls. Therefore I am not using this NuGet. Instead by using a simple HttpClient we can achieve the same.The code below will do the following: Retrieve the access token Set the version to beta Set the endpoint and the action we want to execute Create the HTTP client Set the headers including the authorization bearer header Sending the request which actually is an HTTP get Read the result as a string, since the response will be in JSON formatprivate async Task CallGraphApiBetaChannel(){ // Retrieve the access token var accessToken = await GetAccessToken( "5d1821a3-a004-4cc0-95d5-cb2e797ceaf1", "42903c50-6fc9-40db-a131-87f4522dcf56", "fe_?xg+VhSxe_iq4RSw9TE4AUlddktg8"); // Set the version to beta var graphApiVersion = "beta"; // 'beta' or 'v1.0' // Set the endpoint and the action we want to execute var endpoint = $"https://graph.microsoft.com/{graphApiVersion}"; var action = "/applications"; // Create the http client using (var client = new HttpClient()) using (var request = new HttpRequestMessage(HttpMethod.Get, endpoint + action)) { // Set the headers including the authorization bearer header request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); // Sending the request which actually is a http get using (var response = await client.SendAsync(request)) { if (response.IsSuccessStatusCode) { // Read the result as string, since the response will be json var result = await response.Content.ReadAsStringAsync(); // Do something with the result } } }}After you get the results you can parse the response how you like. Do keep in mind that if you generate a class model from the JSON it can be broken at any moment since they regularly push updates to the beta.If all went right you should be able to retrieve all the available applications in your Azure Active Directory. It is in my opinion re[mark]ably easy to use this and you can change the action variable to any method you can find in the beta reference docs here. Also by using this, you have control over how to parse the responses.Source can be found on my GitHub hereThanks for reading! --- # Azure Sentinel: Taking Security To The Next Level URL: https://www.re-mark-able.net/azure-sentinel-taking-security-to-the-next-level/ Published: 2019-05-03 Tags: Azure Sentinel, Security Just before the RSA 2019 conference, Microsoft announced a new cloud-native SIEM solution called Azure Sentinel. Sentinel is meant to be the extra pair of eyes to keep your enterprise even more secure than before. Threats are more eminent than ever before since more and more companies go to the cloud. Therefore, attackers have more ways to breach your cloud environment. To counter this you can use Sentinel that enables you to ‘Collect’ data across all your users, applications and resources both on-premise and in the cloud. By using Sentinel you can ‘Detect’ threats using predefined use cases like any other SIEM or by using the build in AI. ‘Investigate’ and rapidly respond to threats manually or automatically.Why is this the next step?Currently, there are a lot of different security providers and products within the Microsoft cloud. Think of Azure Security Center or Windows Defender Advanced Threat protection. When one of the security solutions detect a possible malicious activity a SecOps employee has to take a look at what is happening. The employee would then determine what type of alert it is and login into the specific solution portal. For Windows Defender ATP that would look something like below, where in this case the mimikatz tool was downloaded and extracted before windows defender on the specific machine could intervene.What we miss here is all the information that other security solutions could have caught on possibly the same activity. Like how did it get downloaded in the first place (patient zero)? To solve this there should be one central place to get an overview of the entire malicious activity. This is where Sentinel comes in.With Sentinel, you have a far more advanced overview (at time of writing not in public preview yet) of the activity. This would reduce the time spent on figuring out what is happening and instead is spend on solving it and making the affected customer safer.How can Azure Sentinel help?The majority of the CISO who run a SOC (Security Operation Center) to monitor their On-premise IT are hesitant to move to the cloud. In the past, there was a lack of controls to monitor the cloud IT and this sentiment has stuck with the majority of the CISO that we meet. Historically the heart of a SOC is its SIEM (Security Information and Event Management) tool. A SIEM is hard to build and takes a lot of maintenance and time from the technical and security staff. Some key issues with an on-premise SIEM are in my opinion: Hard to set up, there is a steep learning curve and a lot of different data to collect and make sense of. The need for probes, to get the bigger picture you need to install probes and agents. It takes a long time and a lot of skill to configure these properly; Often limited to on-premise IT, while IT tens to migrate to the cloud there is a lack of integration of “cloud log-data”; No machine learning, all logic must come from the SIEM vendor and the data analytics skills of the SecOps team; Slow updates, the AI of the traditional SIEM is embedded in the vendor’s software so in case of a new attack the SIEM will only learn the detection algorithm after a vendor’s update; Not easy scalable, the hard and software requirements need to be planned upfront and are not so easy to change and evolve as the business needs; Expensive to own and operate, to set up and maintain a SIEM there is a need for time and highly skilled SecOps personnel which are both had to come by.Microsoft reimagined the SIEM tool as a new cloud-native solution called Microsoft Azure Sentinel. Some of the key features of Azure Sentinel are: easy to collect security data hybrid IT organization devices users apps servers on any cloudSentinel integrates with all Microsoft (Security) alerts and logging and collaborates with many partners in the Microsoft Intelligent Security Association.Eliminating the need to spend time on: setting up maintaining scaling infrastructureSentinel is already integrated into the Azure portal and comes with build in connectors. All scaling and maintenance (patching) is done automatically.Azure Sentinel Intelligent security analytics at cloud scale and speed, as one Azure tenant gets attacked with a new attack Microsoft’s SecOps investigates and builds new AI for Sentinel and the AI of Sentinel is updated as soon as Microsoft releases it to the cloud. Identifying threats with ML, Azure Sentinel uses state of the art, scalable machine learning algorithms to correlate millions of low-level anomalies to come up with a few high-level security incidents Supported by opensource detection queries, apart from the ML and IA you can set your own triggers and alerts in Sentinel. This can be done by running custom KQL queries. Microsoft has this GitHub for you to get started and share your own.With Azure Sentinel there are no upfront costs, you pay for what you use. This way you can have your SOC in the cloud faster with less effort and costs. Microsoft will let you connect your Office365, Azure AD, Syslog, Azure Security Center, and 3rd party data for free so when the organization moves to the cloud with Sentinel you can still rely on your SOC with SIEM, with the added bonus of the power of the cloud.Taking it to the next levelIn addition to everything an ‘ordinary’ SIEM is capable of, with Sentinel you can also enable “Sentinel Fusion”. Fusion is adding artificial intelligence with advanced machine learning models to your alert detection. Okay great! what does this mean and what does it do?A lot of alerts from the different Microsoft security solutions and providers confront you with low or medium severity detections. With the machine learning models from Sentinel Fusion, you can automatically detect if these ‘not so important’ detections are worth looking into it. The AI will also try to correlate events from different providers through the use of entities. These can be configured in sentinel through something that is called ‘Entity types’. For now, these entities are Account, Host or IP address. As you can see below the use cases you create in Sentinel have the ability to link any column to the appropriate entity type. --- # Can a Azure Static Website really be this cheap? URL: https://www.re-mark-able.net/can-a-azure-static-website-really-be-this-cheap/ Published: 2019-03-09 Tags: Azure Static Website, Serverless, Azure So why should I change to Azure Static Websites? If this is a lot cheaper there are limitations right? Lets put it to the test.What is it?A while ago Microsoft announced the general availability of Azure Static Websites. This means that you can host your website files in a blob storage and host your website from there. You can read all about it here: Microsoft AnnouncementWhat am I doing?For this test we need an actual website that we are able to load and produce some page views with. I got a free template from Colorlib called Appy. You can browse to it by going to https://azurestaticweb.z6.web.core.windows.net/ or by looking at the demo at Colorlib.Since I didn’t want to invest a lot of time into making a new website I deployed this template just “as is” into my blob storage account. This can be done by simply copying all the files into the blob folder called “$web”. It should already be there since it is auto-created after enabling the static web site feature in the storage account. Next up is generating a load on the page.Lets produce some page viewsIn order to get a sense about the cost of the way we are hosting, we are going to produce some page views. To do this a setup a simple Selenium test that does the following: Start a new Firefox window with zero caching Browse to https://azurestaticweb.z6.web.core.windows.net/ Click on “Blog” Click on “Contact”The other menu options will be left out since that are all single page navigation items that produce no load at all. This sequence produces three page views. What we really want to know is how many files are we getting from the blob storage since that. The Firefox network monitor reports that one page view is equal to requesting getting 54 files. Of course, this depends on how your website is built.After this initial call, I put the selenium test in a loop and let it run for over 3 days in a row.How is the performance?All of the above is great but how does this perform on heavier loads? Let’s look at the graphs below that I got from application insights.Number of page views over the last 3 daysNumber of transactions on the blob storage over the last 3 daysAvarage load times for the entire page (loaded all the 54 files)As you may have noticed there is a huge spike in the beginning. This was a typo in my selenium test which caused it to produce 700 page views every minute. While most page views were under 1 second load time, with that many page views it sometimes happened that there was a spike up to 2 seconds.What can we do to improve this?From a storage point of view, I think it is re[mark]able how well it can handle all the page views. Especially since this is data that is not cached. We have a couple of options to speed up while keeping the costs low: Redis Cache Cloudflare Cache Azure Blob Storage CDN Azure Front DoorThe first two options seem nice at first but Redis cache starts at 16 dollars/month which kinda defeats the purpose of low-cost hosting. While Cloudflare is free but requires a purchased custom domain.With the third option, it is possible to replace all your files with versions in the CDN. While I think this is possible to automate it just isn’t that straight forward.The last and in my opinion probably the best option is the Azure Front Door. Although it is still in preview it works really well! The pricing in the preview is 8 cents per GB. For more details, you can have a look here. As you can see in the test results above 20k page views is about 1gb for this template website.Using Azure Front DoorFirst you need to create the Azure Front Door resource. While adding the resource there is a configuration step like belowThere are three steps:Frontend URLsThis is the URL your users are browsing to. There is an option to use a custom domain here.Backend poolsIn the backend pools, you can specify the resources where a frontend URL is pointing to. You can add multiple resources in a pool. The load balancer will switch between them. This makes it possible to create multiple storage accounts in different geo regions and the Front Door load balancer will automatically route you to the nearest resource to reduce loading time.Routing rulesRouting rules are the glue between the frontend URL and the backend pool. The routing rules include lots of settings and one of them is caching. This will reduce the load on your blob storage.After you did these steps your static website will be available within a few minutes on the new *.azurefd.net domain. For me this was https://azurestaticweb.azurefd.net/. Keep in mind that the Azure Static Website is already pretty fast and that Azure Front Door is just an option to either reduce the load time or to scale your application. For now, let’s continue on the Azure Static Website feature.What are the limitations?There is no server running your code so it is not possible to: Install something like Node.js Deploy your ASP.net web appWhat is possible: Using Html, CSS and Javascript Use ReactJs or Angular Use WebAssembly Using Azure Functions as your server-side / backendFinally, What does this 20k page views, 1gig transferred and almost 2 million transactions cost?Well since it is really only the blob storage costs you will see something like this.Notice that the Application insights is “really expensive” in comparison to the Azure Static Web host. But in all fairness, 3 cents (3.12 cents if dollars) is very cheap! This hosting solution is very cheap while still offering a lot of possibilities. As such you can use Azure Functions as your backend e.g. to connect to a database.Thanks for reading! --- # How to develop more secure solutions without the hassle URL: https://www.re-mark-able.net/how-to-develop-more-secure-solutions/ Published: 2019-01-04 Tags: Development, Security As developers, we are constantly trying to implement our solutions in the best way possible. Often we “forget” to look for the vulnerabilities we introduce without really thinking about it. This can happen under pressure of a superior or simply because you can’t know every vulnerability out there.In order to improve this we want to know what is wrong but (I personally) don’t want it to be enforced on every local build we do.. For this to improve I found 2 solutions that work really well without you being bothered all the time.There are 2 different kinds of solutions we can use: Live information and tips during your development Vulnerabilities on added dependenciesSecurity Code ScanFor the first problem, I wanted to be notified during my development in visual studio en visual studio code. This can be done by installing one of the following: Visual Studio -> SecurityCodeScan (preferred!) and/or DevSkim Visual Studio Code -> DevSkimIn this post, we will mainly be looking into Security Code Scan. In order to use this, you can get it either by installing the visual studio extension Link or by adding it as a nuget on the project you want to monitor. I have added it as an extension and therefore will get vulnerability warnings on every solution that is open.After installing, make sure to check the “Enable full solution analysis” in Visual Studio > Tools > Text Editor > C# > Advanced, like in the screenshot below.By now you will get warnings if something is detected. It can present itself in different ways.You will also be able to fix it most of the time with the quickfix option.Last but not least, you can also get an overview of all the warnings in the “Error list” view.In this view, you also have the ability to open the issue in your browser to get additional information, how to fix it and why this is important. I mean you can always ignore it if you think this is not applicable in the current situation.Solutions for vulnerabilities can be found at Security Code Scan and it wil look like:As a second solution, you can also use DevSkim which can be found here but in my opinion, this is less useful and it will produce errors on build time. DevSkim does catch some different possible issues like not secure URLs. Unfortunately, it does not support quick fixes or an explanation of why it is a vulnerability.SnykAfter I implemented a solution, it works and I am ready to deploy it there is a possibility to check it for used dependencies vulnerabilities. This can be done by using Snyk which has a free tier for developers and unlimited tests (runs to check your solution) for public repositories. Keep in mind that for enterprises there are paid options.First, you need to register a free account. This will give you access to your Dashboard. Now you have two options. You can configure a public repository or use a local (on your machine) project. The public repositories can be configured by going to the “Integrations” page where you can configure a lot of providers.In this example we are going to use a local project that is not in any repository since the local project is a little more difficult to setup.So let’s get right to it and install Snyk on your machine. To install Snyk I used npm with the following commandnpm install -g snykAfter that you have to authenticate with your account.snyk authWhich will open the browser and you can login in with your Snyk account. Now you can use it to test your solution by going to project foldercd c:\<your solution folder>In my case, this was a solution with .NET project for an azure function. This is supported but not in the default way. Normally you can just run “sync test” and it will automatically check for a lot of different variations of package files in your current folder (see docs). For .NET projects you need to specify the solution file like thissnyk test --file=MySolution.slnIn the summary of your test, you can already see if there are vulnerabilitiesTo get it in your dashboard on snyk.io you need to runsnyk monitor --file=MySolution.slnThis will send the data to your Snyk account and you will be able to see it in the dashboard and browse through the found vulnerabilities by severity.A nice added bonus to this monitoring is that it will keep your packages config and alert you when there are newly found vulnerabilities. This way you will get an email when this happened and you can respond to that. This can be set to check on a daily or weekly base.Is This Usable?I can only speak for my self but for me, these two steps are easy to implement in local and ci builds and require no hassle to use. An added bonus is that I can use the warnings to improve the solution but I don’t have to. If you want it to take a step further you can always take a look into BinSkim. This tool can analyze your DLL’s and Executables for know vulnerabilities.All in all, I think it is really “remarkable” that all this is free to use while it can have real added value to the solutions we make!