diff --git a/.github/workflows/build-and-deploy-pdf.yml b/.github/workflows/build-and-deploy-pdf.yml index 0525522..63f5ea8 100644 --- a/.github/workflows/build-and-deploy-pdf.yml +++ b/.github/workflows/build-and-deploy-pdf.yml @@ -17,6 +17,28 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Install GitVersion + uses: gittools/actions/gitversion/setup@v0.9.15 + with: + versionSpec: '5.x' + + - name: Determine Version + uses: gittools/actions/gitversion/execute@v0.9.15 + + - name: Print SemVer + run: | + echo ${{ env.GITVERSION_SEMVER }} + echo ${{ env.GitVersion_InformationalVersion }} + echo ${{ env.GitVersion_EscapedBranchName }} + + - name: Update version.tex + shell: bash + run: | + newVersion=${{ env.GitVersion_InformationalVersion }} + sed -i "s|Local-0.1.0|$newVersion|" "src/sections/version.tex" - name: Build PDF uses: xu-cheng/latex-action@v2 @@ -24,11 +46,26 @@ jobs: root_file: "${{ env.FILE_NAME }}.tex" working_directory: src + - name: List src + run: | + ls -lsa src + - name: Upload artifacts uses: actions/upload-artifact@v3 with: - name: "drop" - path: "src/${{ env.FILE_NAME }}.pdf" + name: "${{ env.FILE_NAME }}-${{ env.GitVersion_InformationalVersion }}" + path: | + src/${{ env.FILE_NAME }}.tex + src/${{ env.FILE_NAME }}.bbl + src/${{ env.FILE_NAME }}.bib + src/sections + + - name: Upload artifacts PDF + uses: actions/upload-artifact@v3 + with: + name: "${{ env.FILE_NAME }}-PDF-${{ env.GitVersion_InformationalVersion }}" + path: | + src/${{ env.FILE_NAME }}.pdf - name: Clone repository and add document continue-on-error: true diff --git a/out/SecureAzureOIDC.pdf b/out/SecureAzureOIDC.pdf index 67ec70a..72b0647 100644 Binary files a/out/SecureAzureOIDC.pdf and b/out/SecureAzureOIDC.pdf differ diff --git a/src/SecureAzureOIDC.tex b/src/SecureAzureOIDC.tex index 4b095e6..ac64522 100644 --- a/src/SecureAzureOIDC.tex +++ b/src/SecureAzureOIDC.tex @@ -32,6 +32,8 @@ \author[Petro Kolosov]{Petro Kolosov} \author[Dmitrij Kudryashov]{Dmitrij Kudryashov} \email{kolosovp94@gmail.com} +\urladdr{https://kolosovpetro.github.io} +\email{kudryashov.kd@gmail.com} \keywords{ OpenID Connect, OIDC, @@ -42,7 +44,6 @@ CSRF, ASP .NET Core } -\urladdr{https://kolosovpetro.github.io} \date{\today} \hypersetup{ pdftitle={Secure OpenID Connect implementation using Azure Active Directory and ASP .NET Framework}, @@ -111,10 +112,6 @@ \section{Conclusions}\label{sec:conclusions} \input{sections/conclusions} - - \section{Acknowledgements}\label{sec:acknowledgements} - \input{sections/acknowledgements} - \bibliographystyle{unsrt} \bibliography{SecureAzureOIDC} \noindent \textbf{Version:} \input{sections/version} diff --git a/src/sections/abstract.tex b/src/sections/abstract.tex index f91e72d..0fffc7f 100644 --- a/src/sections/abstract.tex +++ b/src/sections/abstract.tex @@ -1,4 +1,4 @@ -In this manuscript we discuss the problem of secure storage and transfer of access tokens between microservices. +In this manuscript, we discuss the problem of secure storage and transfer of access tokens between microservices. Web browser may store access tokens both, in local storage or in cookie files. We propose a secure implementation to store and transfer auth cookies between microservices -using Azure Active Directory, OpenID Connect and ASP .NET Core. \ No newline at end of file +using Azure Active Directory, OpenID Connect, and ASP .NET Core. \ No newline at end of file diff --git a/src/sections/acknowledgements.tex b/src/sections/acknowledgements.tex deleted file mode 100644 index 99d93db..0000000 --- a/src/sections/acknowledgements.tex +++ /dev/null @@ -1 +0,0 @@ -Thanks someone and somebody for help and useful comments. \ No newline at end of file diff --git a/src/sections/authentication_flow.tex b/src/sections/authentication_flow.tex index c29ab95..701bc71 100644 --- a/src/sections/authentication_flow.tex +++ b/src/sections/authentication_flow.tex @@ -1,35 +1,35 @@ Consider a more practical approach that takes all the previously discussed aspects. -Applying modern frameworks like ASP .NET Core, Angular etc. -let be the following authentication flow as per diagram below +Applying modern frameworks like ASP .NET Core, Angular, etc. +let be the following authentication flow as per the diagram below \begin{figure}[H] \centering \includegraphics[width=1\textwidth]{img/Auth_flow_updated} - ~\caption{Authentication flow diagram.}\label{fig:authentication_flow_diagram} + ~\caption{Authentication flow diagram.} \end{figure} Therefore, the whole authentication process can be described as eight steps such that \begin{enumerate} - \item Compiled Angular frontend application sends request to the authentication endpoint of the ASP .NET Core API - to verify current authentication state. + \item Compiled Angular frontend application sends a request to the authentication endpoint of the ASP .NET Core API + to verify the current authentication state. Angular application is a set of precompiled bundles that are exposed via same ASP .NET Core API at the \texttt{/app} endpoint so that cross-origin requests are not necessary and tokens can be stored in cookie files securely \item Authentication endpoint of the ASP .NET Core API responses either with HTTP status code \texttt{200 (OK)} or \texttt{401 (Unauthorized)} - \item If \texttt{401 (Unauthorized)} status code received from previous step, + \item If \texttt{401 (Unauthorized)} status code received from the previous step, then browser is redirected to the \texttt{login} endpoint of the ASP .NET Core API, otherwise user gets access to the protected resources \item Login method of the ASP .NET Core API redirects browser to the Azure AD authorize url \texttt{login.microsoftonline.com/tenant/oauth2/v2.0/authorize} where user enters his credentials. - It is important to clarify that in order to get ID token we have to put parameter \texttt{openid} to the scope + It is important to clarify that in order to get ID token, we have to put parameter \texttt{openid} to the scope \input{code_snippets/02_openidconnect_add_scope_openid} - \item After successful authentication on the Azure AD side, the browser is redirected to the \texttt{fallback\_url} + \item After successful authentication on the Azure AD side; the browser is redirected to the \texttt{fallback\_url} that is defined in Azure AD application registration. This \texttt{fallback\_url} is an active endpoint of the ASP .NET Core API\@. At this point, the \texttt{TickerStore}~\cite{microsoftIticketstore2023, ticketStore_2023} comes into the flow to manage user sessions. Each session is stored as a \texttt{UserSessionEntity} entity in the database. \input{code_snippets/03_user_session_entity} - The Value property of type \texttt{byte[]} contains serialized \texttt{AuthenticationTicket}~\cite{microsoftAuthenticationTicket2023} + The Value property of type \texttt{byte[]} contains a serialized \texttt{AuthenticationTicket}~\cite{microsoftAuthenticationTicket2023} object such that contains all required information like access, ID and refresh tokens. The class \texttt{TickerStore} implements \texttt{ITickerStore} interface that offers 4 methods: \texttt{StoreAsync, RenewAsync, RetrieveAsync, RemoveAsync}. @@ -47,9 +47,9 @@ Example of \texttt{TicketStore} dependency injection can be found at~\cite{ticketStoreDI_2023}. Authentication cookies are being setup at this step. \item Step 1 is repeated here, but now the HTTP request is for sure to be with \texttt{200 (OK)} status code. - \item Precompiled Angular frontend application now sends request to the another microservice with authentication cookies + \item Precompiled Angular frontend application now sends a request to another microservice with authentication cookies attached to the request's \texttt{Bearer} header using \texttt{YARP} library~\cite{microsoftYarp2021}, so that microservice is accessible. The \texttt{YARP} is configured according to~\cite{yarpDI_2023,yarpSectionAppSettings_2023}. - \item If previous step returns \texttt{401 (Unauthorized)} status code, then Step 1 is repeated + \item If a previous step returns \texttt{401 (Unauthorized)} status code, then Step 1 is repeated \end{enumerate} \ No newline at end of file diff --git a/src/sections/conclusions.tex b/src/sections/conclusions.tex index 5b47933..da23b72 100644 --- a/src/sections/conclusions.tex +++ b/src/sections/conclusions.tex @@ -1,6 +1,6 @@ -In this manuscript we explore the problem of secure storage and transfer of access tokens between microservices. +In this manuscript, we explore the problem of secure storage and transfer of access tokens between microservices. Particular attention was paid to possible vulnerabilities during transfer of access tokens such -as Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF). +as Cross-Site Scripting and Cross-Site Request Forgery. To eliminate these vulnerabilities, it is necessary to store authorization tokens in cookies with mandatory \texttt{HttpOnly} and \texttt{SameSite} settings such that \texttt{SameSite} values should be \texttt{Lax} or \texttt{Strict}. @@ -12,7 +12,7 @@ Also, we provide an authentication / authorization implementation based on the ASP.NET Core Web API backend and Angular frontend application. -These applications are stored under the single domain to eliminate necessity to transfer authorization cookies cross domain way. +These applications are stored under the single domain to eliminate the necessity to transfer authorization cookies cross domain way. Transfer of access tokens between microservices is implemented using Reverse Proxy YARP~\cite{microsoftYarp2021} so that the access token is automatically substituted in the request header. diff --git a/src/sections/definitions.tex b/src/sections/definitions.tex index 2136140..6740575 100644 --- a/src/sections/definitions.tex +++ b/src/sections/definitions.tex @@ -1,12 +1,12 @@ \begin{itemize} - \item \textbf{Access Token} is credential used to access protected resources. + \item \textbf{Access Token} is a credential used to access protected resources. An access token is an opaque string representing an authorization issued to the client. The string is usually opaque to the client. Tokens represent specific scopes and durations of access, granted by the resource owner, and enforced by the resource server and authorization server. - \item \textbf{Refresh Token} is credential used to obtain a new pair of access and refresh tokens when the becomes - invalid or expires, or to obtain additional access tokens with identical or narrower scope (access tokens may have a shorter - lifetime and fewer permissions than authorized by the resource owner). + \item \textbf{Refresh Token} is a credential used to obtain a new pair of access and refresh tokens when they become + invalid or expired, or to obtain additional access tokens with identical or narrower scope. + Access tokens may have a shorter lifetime and fewer permissions than authorized by the resource owner. Refresh tokens are issued to the client by the authorization server. \item \textbf{Resource Owner} is an entity capable of granting access to a protected resource. When the resource owner is a person, it is referred to as an end-user. diff --git a/src/sections/introduction_to_open_id_connect.tex b/src/sections/introduction_to_open_id_connect.tex index 1c1652b..f51a2bc 100644 --- a/src/sections/introduction_to_open_id_connect.tex +++ b/src/sections/introduction_to_open_id_connect.tex @@ -1,11 +1,3 @@ -%Your introduction here. -%Include some references~\cite{siddiqui2011cross,spett2005cross, bradley2015rfc,hardt2012oauth,fielding2014rfc}. -%Lorem Ipsum is simply dummy text of the printing and typesetting industry. -%Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley -%of type and scrambled it to make a type specimen book. -%It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. -%It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more -%recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. OpenID Connect (OIDC) is a simple identity layer~\cite{siriwardenaOpenid2020, sakimuraOpenid2014} on top of the OAuth 2.0 protocol~\cite{hardt2012oauth}. It enables Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, @@ -19,12 +11,11 @@ OpenID Connect uses them to provide identity services. The problem OAuth 2.0 solves is that in the traditional client-server authentication model, -the client requests an access-restricted resource (protected resource) +the client requests an access-restricted resource on the server by authenticating with the server using the resource owner's credentials. In order to provide third-party applications access to restricted resources, the resource owner shares its credentials with the third party. This creates several problems and limitations~\cite{hardt2012oauth}: - \begin{itemize} \item Third-party applications are required to store the resource owner's credentials for future use, typically a password in clear-text. @@ -36,21 +27,6 @@ \item Compromise of any third-party application results in compromise of the end-user's password and all the data protected by that password. \end{itemize} - -%1. Third-party applications are required to store the resource owner's credentials for future use, typically -%a password in clear-text. -% -%2. Servers are required to support password authentication, despite the security weaknesses inherent in passwords. -% -%3. Third-party applications gain overly broad access to the resource owner's protected resources, -%leaving resource owners without any ability to restrict duration or access to a limited subset of resources. -% -%4. Resource owners cannot revoke access to an individual third party without revoking access to all third parties, -%and must do so by changing the third party's password. -% -%5. Compromise of any third-party application results in compromise of the end-user's password -%and all the data protected by that password. - OAuth 2.0 addresses these issues by introducing an authorization layer and separating the role of the client from that of the resource owner. In OAuth, the client requests access to resources controlled by the resource owner and hosted by the resource server. @@ -59,20 +35,19 @@ \begin{figure}[H] \centering \includegraphics[width=1\textwidth]{img/OAuthPkceScheme_1570_1055} - ~\caption{OAuth 2.0 with PKCE flow diagram.}\label{fig:oauth_with_pkce} + ~\caption{OAuth 2.0 with PKCE flow diagram.} \end{figure} \begin{enumerate} \item After clicking on the \texttt{Sign in with Google} button, - the browser is redirected to the authorization endpoint, where the resource owner (user) enters credentials e.g.\ login and password. - \item After successful authentication the browser is redirect to \texttt{redirect\_uri} defined in OAuth provider settings. + the browser is redirected to the authorization endpoint, where the resource owner (user) enters credentials e.g., login and password. + \item After successful authentication, the browser is redirect to \texttt{redirect\_uri} defined in OAuth provider settings. The \texttt{code} parameter is attached to the request parameters. \item Having the \texttt{code} value application exchanges it to a pair of access and refresh tokens. - Provided that we used PKCE with specified \texttt{code\_challenge} and \texttt{code\_challenge\_method} values exchanging code to a pair of tokens + If we used PKCE with specified \texttt{code\_challenge} and \texttt{code\_challenge\_method} values exchanging code to a pair of tokens, we must pass the value of \texttt{code\_verifier} to the request. \end{enumerate} - -We mention here such definitions as code and state and they means +We mention here such definitions as code and state, and they mean \begin{itemize} \item \textbf{Code} is an authorization code that is obtained through an authorization server and mediates between clients and resource owners. @@ -82,42 +57,21 @@ their credentials are never sent to the client. \item \textbf{State} is the value used by the client to store the state between the authorization request and the callback. The authorization server enables this value when redirecting the user agent back to the client. - This parameter is used to prevent Cross-Site Request Forgery (CSRF) attacks. + This parameter is used to prevent CSRF attacks. \end{itemize} Adding the Proof of Key Code Exchange (PKCE) to the OIDC flow improves protocol security so that the code cannot be exchanged by third-party applications by-passing the original application. -Authorization code flow with PKCE is a protocol that represents a client generated secret that can be verified +Authorization code flow with PKCE is a protocol that represents a client-generated secret that can be verified by an authorization server. This secret is called \texttt{code\_verifier}. The client hashes the \texttt{code\_verifier} value and writes it to the \texttt{code\_challenge} parameter of an HTTP request. -Proof of Key Code Exchange (PKCE) solves the problem of secure code exchange. +PKCE solves the problem of secure code exchange. If an attacker manages to get an authorization code, then he will not be able to exchange it for access and refresh tokens. Therefore, we ensure that the exchange of a code for tokens is produced by the same application that performed the authentication. Proof of Key Code Exchange can be compared to the digital signature of an authentication process. -To exchange the \texttt{code} for a pair of access and refresh tokens it is necessary to specify -a valid \texttt{code\_verifier}. - -%Code is an authorization code that is obtained through an authorization -%server and mediates between clients and resource owners. -%Before the authorization server redirects the resource owner back to the client, -%the authorization server verifies the authenticity of the resource owner. -%So because the resource owner only authenticates with the authorization server, -%their credentials are never sent to the client. -% -%State is the value used by the client to store the state between the authorization request and the callback. -%The authorization server enables this value when redirecting the user agent back to the client. -%This parameter is used to prevent Cross-Site Request Forgery (CSRF) attacks. - -%1. After clicking on the "Sign in with Google" button, -%the browser is redirected to the authorization endpoint, where the resource owner (user) enters credentials e.g. login and password. -% -%2. After successful authentication the browser is redirect to redirect_uri defined in OAuth provider settings. -%Code parameter is attached to the request parameters. -% -%3. Having the code value application exchanges it to a pair of access and refresh tokens. -%Provided that we used PKCE with specified code_challenge and code_challenge_method values exchanging code to a pair of tokens -%we must pass the value of code_verifier to the request. \ No newline at end of file +To exchange the \texttt{code} for a pair of access and refresh tokens, it is necessary to specify +a valid \texttt{code\_verifier}. \ No newline at end of file diff --git a/src/sections/refresh_token_flow.tex b/src/sections/refresh_token_flow.tex index 544e2fd..5f25aee 100644 --- a/src/sections/refresh_token_flow.tex +++ b/src/sections/refresh_token_flow.tex @@ -1,17 +1,17 @@ The implementation of refreshing user tokens is extremely simple. It is necessary to create a background service~\cite{microsoftHostedservice2023} that manages sessions, -in particular deletes sessions that has not been used long time, refreshes existing sessions etc. +in particular deletes sessions that have not been used long time, refresh existing sessions, etc. In case of refresh or initial authentication, the new \texttt{AuthenticationTicket} object~\cite{microsoftAuthenticationTicket2023} replaces the existing or new instance is created. In addition, the Azure AD authentication server's response contains a timestamp property \texttt{ExpiresIn} -that determines lifetime of the tokens, +that determines the lifetime of the tokens, the background service updates the \texttt{ExpiresAt} property of the \texttt{UserSessionEntity} accordingly. The background service is responsible not only for refreshing the sessions, but also it is responsible for deleting the sessions that have not been used for a long time. Once per predefined period, the sessions are selected and their \texttt{DateOfLastAccess} property is compared to the current \texttt{DateTime.Now}. -If the difference between the \texttt{DateOfLastAccess} and \texttt{DateTime.Now} is more than, for example 3 days, -then session is deleted. +If the difference between the \texttt{DateOfLastAccess} and \texttt{DateTime.Now} is more than, for example, 3 days, + then the session is deleted. Each time a user performs an action on the site, the \texttt{DateOfLastAccess} property is updated. Implementation of a background service can be done as per references~\cite{backroundService_2023, configurationBackgroundService_2023} \ No newline at end of file diff --git a/src/sections/statement_of_the_problem.tex b/src/sections/statement_of_the_problem.tex index 461427c..2a017d1 100644 --- a/src/sections/statement_of_the_problem.tex +++ b/src/sections/statement_of_the_problem.tex @@ -1,17 +1,17 @@ -In this manuscript we discuss the problem of secure storage and transfer of access tokens between microservices. +In this manuscript, we discuss the problem of secure storage and transfer of access tokens between microservices. Web browser may store access tokens both, in local storage or in cookie files. Local storage is a web browser mechanism that allows web applications to store data locally on the user's device. -It is important to note that Local storage is vulnerable to Cross Site Scripting (XSS) attacks~\cite{spett2005cross}. -Cross Site Scripting (XSS) is a type of attack such that malicious JavaScript code is injected into an html-page -to access user's sensitive data, for example access tokens. -Cross Site Scripting (XSS) attacks may be divided by following groups: +It is important to note that Local storage is vulnerable to Cross-Site Scripting attacks~\cite{spett2005cross}. +Cross-Site Scripting is a type of attack such that malicious JavaScript code is injected into an html-page +to access user's sensitive data, for example, access tokens. +Cross-Site Scripting (XSS) attacks may be divided by following groups: \begin{itemize} \item \textbf{Reflected XSS} is a type of attack in which a malicious - the script is passed to the web server via URL or form parameters and then returned back to the page's html code + script is passed to the web server via URL or form parameters and then returned back to the page's html code without proper filtering or escaping.\ If the user opens the page, then the script is executed in the browser, which can lead to the loss of sensitive data, such as access tokens. - \item \textbf{Stored XSS} is a type of attack in which a malicious script is stored on the server, for example + \item \textbf{Stored XSS} is a type of attack in which a malicious script is stored on the server, for example, in the database and displayed on web pages.\ The script is executed in users' browsers, requesting pages with malicious code. \item \textbf{XSS in the DOM} is a type of attack such that a malicious script modifies the DOM tree of a web page, @@ -19,9 +19,9 @@ \end{itemize} Another way to store credentials is to store them in cookie files. -Cookies are small pieces of data sent by web server and stored on user's device. +Cookies are small pieces of data sent by web server and stored on a user's device. Storing access tokens in cookies eliminates potential XSS attacks since that HttpOnly setting -makes impossible to read cookies using JavaScript code. +makes it impossible to read cookies using JavaScript code. Having credentials stored in cookies, HTTP request is performed via JavaScript. If the object \texttt{\{ withCredentials: true \}} provided and auth cookies exist, then auth cookies are attached to request, but cannot be accessed from JS code anyway. @@ -29,30 +29,30 @@ \input{code_snippets/01_http_request_ts} -Note that cookie files are vulnerable to Cross-Site Request Forgery (CSRF) attacks~\cite{siddiqui2011cross}. -Cross-Site Request Forgery (CSRF) -- is an attack such that redirects user to the resource where user has active session. +Note that cookie files are vulnerable to Cross-Site Request Forgery attacks~\cite{siddiqui2011cross}. +Cross-Site Request Forgery is an attack such that redirects user to the resource where user has an active session. It means that attacker could perform requests to resources on behalf of the user. The main idea of Cross-Site Request Forgery (CSRF) attack is illustrated below \begin{figure}[H] \centering \includegraphics[width=1\textwidth]{img/Csrf_diagram} - ~\caption{Cross-Site Request Forgery (CSRF) principle diagram.}\label{fig:csrf_diagram} + ~\caption{CSRF attack principle diagram.}\label{fig:csrf_diagram} \end{figure} Cookie files provided with \texttt{SameSite} setting that determines whether cookies will be sent -along with cross domain requests. +along with cross-domain requests. \texttt{SameSite} setting has one of the states below: \begin{itemize} - \item \textbf{None} -- means no restrictions are imposed on the transfer of cookies. - \item \textbf{Lax} -- allows cookie transmission only by secure HTTP methods according to RFC 7231~\cite{fielding2014rfc}. + \item \textbf{None} means no restrictions are imposed on the transfer of cookies. + \item \textbf{Lax} allows cookie transmission only by secure HTTP methods, according to RFC 7231~\cite{fielding2014rfc}. These methods are \texttt{GET, HEAD, OPTIONS} and \texttt{TRACE}. - \item \textbf{Strict} -- blocks cookies from being sent with any requests from third-party resources. - Cookies will only be transferred within same domain. + \item \textbf{Strict} blocks cookies from being sent with any requests from third-party resources. + Cookies will only be transferred within the same domain. \end{itemize} Therefore, \texttt{SameSite} setting values such as \texttt{Lax} and \texttt{Strict} protect user from a CSRF attack -blocking submission of cookies using unsecure HTTP methods and cross domain requests. +blocking submission of cookies using unsecure HTTP methods and cross-domain requests. There are more CSRF protection techniques in~\cite{owaspCsrf}. \ No newline at end of file