OneDrive / onedrive-api-docs

Official documentation for the OneDrive API
MIT License
450 stars 227 forks source link

File Picker v8 in iframe - Content Security Policy issue #1621

Closed joshirakesh closed 1 year ago

joshirakesh commented 2 years ago

We're hosting the file picker within an iframe using the procedures outlined in the instructions here. Sometimes picker refuses to connect and throws the following content security policy issue.

Refused to frame 'https://{{tenant}}.sharepoint.com/' because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'self' teams.microsoft.com *.teams.microsoft.com *.skype.com *.teams.microsoft.us local.teams.office.com *.powerapps.com *.yammer.com *.officeapps.live.com *.office.com *.stream.azure-test.net *.microsoftstream.com *.dynamics.com *.microsoft.com securebroker.sharepointonline.com".

We do not set the src of the iframe ourselves, but rather, as stated in the documentation, we use a POST request with a valid access token in the form parameters to load FilePicker.aspx.

❌ Here's an example of a post request when it failed to load:

Request

Request URL: https://{tenant}.sharepoint.com/sites/Verifyit/_layouts/15/FilePicker.aspx?filePicker=%7B%22sdk%22%3A%228.0%22%2C%22entry%22%3A%7B%22sharePoint%22%3A%7B%22byPath%22%3A%7B%22list%22%3A%22https%3A%2F%2Ffigg.sharepoint.com%2Fsites%2FVerifyit%2FShared+Documents%22%2C%22folder%22%3A%22General%22%7D%7D%7D%2C%22authentication%22%3A%7B%7D%2C%22messaging%22%3A%7B%22origin%22%3A%22https%3A%2F%2Fapp.boarddecisions.com%22%2C%22channelId%22%3A%22d6c0a0f6-5610-48fc-a312-1ca15bf0b2f1%22%7D%2C%22typesAndSources%22%3A%7B%22mode%22%3A%22files%22%2C%22pivots%22%3A%7B%22sharedLibraries%22%3Atrue%2C%22recent%22%3Atrue%2C%22oneDrive%22%3Atrue%7D%7D%2C%22selection%22%3A%7B%22mode%22%3A%22single%22%7D%7D
Request Method: POST
Status Code: 200  (from service worker)

Response Headers

content-encoding: gzip
content-security-policy: frame-ancestors 'self' teams.microsoft.com *.teams.microsoft.com *.skype.com *.teams.microsoft.us local.teams.office.com *.powerapps.com *.yammer.com *.officeapps.live.com *.office.com *.stream.azure-test.net *.microsoftstream.com *.dynamics.com *.microsoft.com securebroker.sharepointonline.com;
content-type: text/html; charset=utf-8
date: Tue, 23 Aug 2022 03:41:51 GMT
microsoftsharepointteamservices: 16.0.0.22810
ms-cv: oF2vesywAEDF2FaFQRz7Sw.0
nel: {"report_to":"network-errors","max_age":7200,"success_fraction":0.001,"failure_fraction":1.0}
p3p: CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI"
referrer-policy: no-referrer, strict-origin-when-cross-origin
report-to: {"group":"network-errors","max_age":7200,"endpoints":[{"url":"https://spo.nel.measure.office.net/api/report?tenantId=c7105dda-a548-4def-8ee7-e992e0e6dcb0&destinationEndpoint=Edge-Prod-BOM01r5c&frontEnd=AFD"}]}
request-id: 7aaf5da0-b0cc-4000-c5d8-5685411cfb4b
spiislatency: 0
sprequestduration: 72
sprequestguid: 7aaf5da0-b0cc-4000-c5d8-5685411cfb4b
strict-transport-security: max-age=31536000
vary: Accept-Encoding
x-1dscollectorurl: https://eu-mobile.events.data.microsoft.com/OneCollector/1.0/
x-ariacollectorurl: https://browser.pipe.aria.microsoft.com/Collector/3.0/
x-aspnet-version: 4.0.30319
x-cache: CONFIG_NOCACHE
x-content-type-options: nosniff
x-databoundary: None
x-frame-options: SAMEORIGIN
x-ms-invokeapp: 1; RequireReadOnly
x-msedge-ref: Ref A: D805021C3D084F7F9D33A283CE13EFA6 Ref B: BOM01EDGE1610 Ref C: 2022-08-23T03:41:52Z
x-powered-by: ASP.NET
x-sharepointhealthscore: 2

We noticed that it works properly when we reopen it in the same browser session.

✅ Here's an example of a post request when it loaded correctly:

Request

Request URL: https://{tenant}.sharepoint.com/sites/Verifyit/_layouts/15/FilePicker.aspx?filePicker=%7B%22sdk%22%3A%228.0%22%2C%22entry%22%3A%7B%22sharePoint%22%3A%7B%22byPath%22%3A%7B%22list%22%3A%22https%3A%2F%2Ffigg.sharepoint.com%2Fsites%2FVerifyit%2FShared+Documents%22%2C%22folder%22%3A%22General%22%7D%7D%7D%2C%22authentication%22%3A%7B%7D%2C%22messaging%22%3A%7B%22origin%22%3A%22https%3A%2F%2Fapp.boarddecisions.com%22%2C%22channelId%22%3A%22d0a8bf26-cb59-46d1-abd4-ba78de7aa49c%22%7D%2C%22typesAndSources%22%3A%7B%22mode%22%3A%22files%22%2C%22pivots%22%3A%7B%22sharedLibraries%22%3Atrue%2C%22recent%22%3Atrue%2C%22oneDrive%22%3Atrue%7D%7D%2C%22selection%22%3A%7B%22mode%22%3A%22single%22%7D%7D
Request Method: POST
Status Code: 200  (from service worker)

Response Headers

cache-control: private
content-encoding: gzip
content-type: text/html; charset=utf-8
date: Tue, 23 Aug 2022 03:41:52 GMT
microsoftsharepointteamservices: 16.0.0.22810
ms-cv: oF2veyCwAEDF2Fw2AHJR9Q.0
nel: {"report_to":"network-errors","max_age":7200,"success_fraction":0.001,"failure_fraction":1.0}
p3p: CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI"
referrer-policy: no-referrer, strict-origin-when-cross-origin
report-to: {"group":"network-errors","max_age":7200,"endpoints":[{"url":"https://spo.nel.measure.office.net/api/report?tenantId=c7105dda-a548-4def-8ee7-e992e0e6dcb0&destinationEndpoint=Edge-Prod-BOM01r5c&frontEnd=AFD"}]}
request-id: 7baf5da0-b020-4000-c5d8-5c36007251f5
spiislatency: 1
sprequestduration: 88
sprequestguid: 7baf5da0-b020-4000-c5d8-5c36007251f5
strict-transport-security: max-age=31536000
vary: Accept-Encoding
x-1dscollectorurl: https://eu-mobile.events.data.microsoft.com/OneCollector/1.0/
x-ariacollectorurl: https://browser.pipe.aria.microsoft.com/Collector/3.0/
x-aspnet-version: 4.0.30319
x-cache: CONFIG_NOCACHE
x-content-type-options: nosniff
x-databoundary: None
x-ms-invokeapp: 1; RequireReadOnly
x-msedge-ref: Ref A: 0F3FE8D2A85943609F35C3801CD7F0AD Ref B: BOM01EDGE1610 Ref C: 2022-08-23T03:41:53Z
x-powered-by: ASP.NET
x-sharepointhealthscore: 0

When it loads correctly, there are no 'content-security-policy' response headers.

Could you please help us in identifying what is causing this and how to resolve it?


Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

ghost commented 2 years ago

Thank you for your contribution to OneDrive API Docs. We will be triaging your incoming issue as soon as possible.

ThomasMichon commented 2 years ago

@joshirakesh, when you make the POST request to FilePicker.aspx, you need to include a form parameter for access_token. The access_token needs to be obtained from MSAL with the 'audience' set to the domain from your URL. If you don't send the token, the response will enforce the Content Security Policy. This is intended to protect the user from click-jacking by an arbitrary host application.

patrick-rodgers commented 1 year ago

Please see the updated docs here.

Closing this issue as answered. If you have additional questions or we did not answer your question, please open a new issue, ref this issue, and provide any additional details available. Thank you!

adevine commented 1 month ago

I know this is a closed issue, but if you see this @ThomasMichon and/or @patrick-rodgers - in the comment above you state "The access_token needs to be obtained from MSAL with the 'audience' set to the domain from your URL." I searched around a bit and it wasn't clear to me how to ensure this 'audience' value is set. Right now I'm getting a token like the below code:

const app = await PublicClientApplication.createPublicClientApplication({
    auth: {
        authority: "https://login.microsoftonline.com/common", // for consumers I use https://login.microsoftonline.com/consumers
        clientId: hookConfig.clientId,
        redirectUri: window.location.origin,
    },
});

// for authParams below I use { scopes: ["OneDrive.ReadOnly"] } for consumers and { scopes: [".default"] } for work/school accounts
try {
    const resp = await app.acquireTokenSilent(authParams);
    accessToken = resp.accessToken;
} catch (e) {
    // per examples we fall back to popup
    const resp = await app.loginPopup(authParams);
    app.setActiveAccount(resp.account);

    if (resp.idToken) {
        const resp2 = await app.acquireTokenSilent(authParams);
        accessToken = resp2.accessToken;
    } else {
        throw e;
    }
}

Currently my code works for consumer accounts, but for work/school accounts I am getting the CSP frame-ancestors error. Is it that I need to update the scopes to something besides just [".default"] to get this to work? I just couldn't find anything online about setting an 'audience' param or config value.