Questions and discussions about using the Shopify CLI and Shopify-built libraries.
Hi there,
Recently I attempted to submit an alternative payment gateway to the shopify store and was almost immediately rejected with the following:
App must set security headers to protect against clickjacking.
Your app must set the proper frame-ancestors content security policy directive to avoid clickjacking attacks. The 'content-security-policy' header should set frame-ancestors https://[shop].myshopify.com https://admin.shopify.com, where [shop] is the shop domain the app is embedded on.
And I'm wondering - do these headers have to be present on the installation of the app?
Or are we expected to set them upon redirect to the app for the alternative payment gateway flow. Just wondering where in the order of operations these need to exist.
Hi did you manage to resolve this issue ?
Hi
Is it OK to display this in the response header?
content-security-policy frame-ancestors https://*.myshopify.com https://admin.shopify.com
how can i resolve this issue because that my app was rejected constantly PLz Guaid
I don't quite understand what you mean. Can you explain it more clearly? Thanks.
Thanks for Replay
Actually I have made a public app on Shopify partner, when I send that app for review, then this error is there. So do you have any idea about this error?
I am creating a public app and when it was sent for review this is the error which we are facing right now. Can you please help me in resolving it thanks.
The Error:
App must set security headers to protect against clickjacking.
Your app must set the proper frame-ancestors content security policy directive to avoid clickjacking attacks. The 'content-security-policy' header should set frame-ancestors https://[shop].myshopify.com https://admin.shopify.com, where [shop] is the shop domain the app is embedded on.
And I'm wondering - do these headers have to be present on the installation of the app?
Or are we expected to set them upon redirect to the app for the alternative payment gateway flow. Just wondering where in the order of operations these need to exist.
Hi
I had the same issue and what solved that error for me was adding the headers in the next.config file, I did it exatcly using the NextJS documentation here
Where the key is "Content-Security-Policy" and the value is "frame-ancestors https://[shop].myshopify.com https://admin.shopify.com/;"
I have tried the link you shared Luckily I am using NextJs but still My account got rejected after review with same issue. What should I do now ?
I have a question. How did you pass the value for [shop] to the headers function in next.config.js,
because it's should be something like this: "frame-ancestors https://example-shop.myshopify.com https://admin.shopify.com/;
I have used the value as mentioned in the link.
Can you share an example of how you manage to create it ?
Thanks in advance
I don't know if this will help you, but this is how I tried to solve the problem (I'm still waiting for the review of my app):
I assume you also use React.js if you have the next.config.js file in your project.
In server.js I have defined a new function:
// Defense against clickjacking: https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html
// https://shopify.dev/apps/store/security/iframe-protection
// Only allow Shop host url to display site in iFrame
const setClickJackingHeadersMiddleware = async (ctx, next) => {
const shop = ctx.query.shop;
try {
if (shop) {
ctx.set({
"Content-Security-Policy": `frame-ancestors https://${shop} https://admin.shopify.com;`,
});
console.log(
"Set Content-Security-Policy to: ",
`frame-ancestors https://${shop} https://admin.shopify.com;`
);
} else {
}
} catch (err) {
console.log("Doesnt matter");
} finally {
return next();
}
};
And this function is called by the router before any other router is defined:
router.use(setClickJackingHeadersMiddleware);
I will keep you updated if it has worked.
I could also create a gist on Github so you can see my complete server.js file if you want to.
Sure thanks will let u know
You are also trying for public app right ? or embedded ?
same error again
Can You Please Help me in resolving this issue ? I am stuck here. Help is appreciated.
Thanks
ISSUE
Requirements that must be met before initial screening | |
|
I have passed the information exactly the same way. Still same issue What should i do now please help
we are same boat, I wonder this forum has no official support reply in a week.....
But your issue was resolved right ?
Hey can you do me a favor like if you can share your coding with me regarding this issue only.
This would mean alot.
Thanks
still reject from Shopify, but the email don't specific which page with url encounter the problem, it quite bad dev experience.
I 100% sure I add the following line on every page and using F12 dev tool to check the header is exist.
to add the header is simple add
OK Thanks
I will update you after checking
nice, ill try this out
@DenisSabolotni can you please send the screenshot of network tab request with header
I also have these issue and I ensure I have add the header via PHP on EVERY page
Hi guys!
I have found a solution that passed the review!
I coudn't find a way to insert a variable in the next.config file, if that variable wasnt defined in the dotenv file.
Now I'll share a screen shot of how did I do it. (I am using a project generated with the Shopify CLI)
In server.js
Hopefully this help you out guys!
Ok will get to you on this one.
you were using Next.js right ?
@juanmaptag so I tried your solution, but this will resolve in another error when trying to install the app in an test shop:
AppBridgeError: APP::ERROR::INVALID_CONFIG: host must be provided
and the Shopify review is getting declined with the following reason:
Required changes | |
|
I have finally found a working solution (all code changes are made in server.js):
I'm using the npm package koa-helmet (v6.1.0) (not necessary, can also be done without)
import helmet from "koa-helmet";
and almost right after the app.prepare statement, I have defined a new middleware function called setContentSecurityHeader. The problem with my other solution before was, that it has not always initialized the Clickjacking header correctly, especially before authentication, the header has not been set.
app.prepare().then(async () => {
const server = new Koa();
const router = new Router();
const setContentSecurityHeader = (ctx, next) => {
// Cookie is set after auth
if (ctx.cookies.get("shopOrigin")) {
return helmet.contentSecurityPolicy({
directives: {
defaultSrc: helmet.contentSecurityPolicy.dangerouslyDisableDefaultSrc,
frameAncestors: [
`https://${ctx.cookies.get("shopOrigin")}`,
"https://admin.shopify.com",
],
},
})(ctx, next);
} else {
// Before auth => no cookie set...
return helmet.contentSecurityPolicy({
directives: {
defaultSrc: helmet.contentSecurityPolicy.dangerouslyDisableDefaultSrc,
frameAncestors: [
`https://${ctx.query.shop}`,
"https://admin.shopify.com",
],
},
})(ctx, next);
}
};
server.use(setContentSecurityHeader);
And as a final step, I initialize a cookie right after authentication. This cookie ensures, that the header is set correctly for each following request after authentication.
server.use(
createShopifyAuth({
async afterAuth(ctx) {
const { shop, accessToken, scope } = ctx.state.shopify;
// set shopOrigin cookie, so it can be used for click jacking header
ctx.cookies.set("shopOrigin", shop, {
httpOnly: false,
secure: true,
sameSite: "none",
});
const host = ctx.query.host;
ACTIVE_SHOPIFY_SHOPS[shop] = scope;
Hope this helps.
@DenisSabolotni Does this solution really pass app review? Aren't third-party cookies forbidden in embedded apps as of this year?
yea i tried this and it does work, did pass through the review
Hi, To solve the clickjacking headers issue in next/react use below code in getInitialProps in _app.js. Thanks.
ctx.res.setHeader('Content-Security-Policy',`frame-ancestors https://${ctx.query.shop} https://admin.shopify.com`);
There are two solutions for this if you're working with next app with node.js. Both solutions worked for me.
First Solution:
In your server file add the following code:
appRouter.get("(.*)", async (ctx) => {
const shop = ctx.query.shop as string;
if (shop) ctx.set("Content-Security-Policy", `frame-ancestors https://${shop} https://admin.shopify.com`);
await handleRequest(ctx);
});
Second Solution:
Add the following code to your home page in next.js. It will be an index.tsx, index.jsx file in your pages directory
export async function getServerSideProps(context: any) {
if (context?.query?.shop)
context.res.setHeader(
"Content-Security-Policy",
`frame-ancestors https://${context.query.shop} https://admin.shopify.com`,
);
return {
props: {},
};
}
Hello there,
I just wanted to update you all, that this is not a problem anymore if you generate your project with the most recent Shopify-CLI.
The code is already there and it looks like this:
app.use((req, res, next) => {
const shop = req.query.shop;
if (Shopify.Context.IS_EMBEDDED_APP && shop) {
res.setHeader(
"Content-Security-Policy",
`frame-ancestors https://${shop} https://admin.shopify.com;`
);
} else {
res.setHeader("Content-Security-Policy", `frame-ancestors 'none';`);
}
next();
});
The code looks very different in comparison to the older versions, so if you want to look into that in detail, just get the newest Shopify CLI version, generate a new project and copy the code parts you need.
Happy that Shopify reacted to feedback and now we don't have to deal with that problem anymore.
I tried to submit my second app today, and suddently started getting this error again.
I'm now afraid to submit the app again, because shopify bans your account if your app gets rejected too many times. I'm using a solution similar to your last post on all routes and still get this error:
Your app must set the proper frame-ancestors content security policy directive to avoid clickjacking attacks. The 'content-security-policy' header should set frame-ancestors https://[shop].myshopify.com https://admin.shopify.com, where [shop] is the shop domain the app is embedded on.