Skip to content

Instantly share code, notes, and snippets.

@cprima
Last active March 19, 2025 00:40
Show Gist options
  • Save cprima/5c0fb0d8d2a6e2969e65ee9a9a74685c to your computer and use it in GitHub Desktop.
Save cprima/5c0fb0d8d2a6e2969e65ee9a9a74685c to your computer and use it in GitHub Desktop.
Bypass X-Frame-Options: PHP Proxy for iframe Embedding

PHP Proxy Script for Iframe Embedding

Description

This PHP script is a server-side proxy designed to bypass restrictions that prevent embedding external websites within iframes. Many websites use security headers (e.g., X-Frame-Options or Content-Security-Policy) to block their content from being displayed in iframes, leading to errors like "Content refused to connect." when trying to embed them directly. This proxy script retrieves the content server-side, modifies it, and delivers it to the iframe, effectively circumventing these restrictions.

Use Case

This script is particularly useful for integrating external web pages into Reveal.js presentations. Reveal.js allows the use of iframes to display content during slideshows. However, embedding some web pages directly often fails due to security restrictions. By using this proxy script, users can include external content seamlessly in their presentations without encountering connection errors.

Why is This Needed?

  • Bypassing Security Headers: Websites commonly set headers like X-Frame-Options: DENY or Content-Security-Policy: frame-ancestors 'none'; to prevent other sites from embedding their content. This proxy script circumvents these restrictions by fetching and serving the content server-side, enabling it to be displayed in an iframe. However, it is important to note that bypassing security headers may violate the terms of service of some websites, so use this script responsibly.
  • Handling Relative URLs: Even when embedding is allowed, external web pages often use relative URLs that may not load correctly when proxied. The script parses and rewrites these URLs to ensure that all resources load properly.
  • Simplified Embedding: Instead of dealing with errors and manually adjusting content, users can leverage this script to reliably embed any web page into their iframe without modifying the source.

How It Works

  1. Server-Side Fetching: The script takes a URL as input, validates it, and fetches the content using cURL.
  2. URL Rewriting: It scans the HTML content for relative and absolute URLs (e.g., in src, href, action attributes, and JavaScript) and converts them to proxied URLs based on the base URL.
  3. Bypass Restrictions: Since the content is fetched and modified server-side, restrictive headers that normally prevent embedding (e.g., X-Frame-Options, Content-Security-Policy) are removed, allowing the content to be embedded.
  4. Response Delivery: The processed HTML is sent to the client, ensuring it renders correctly within the iframe, including any dynamically loaded resources.

Usage

  1. Download and Deploy the script to your server.
  2. Access the Script via a URL:
    https://yourserver.com/iframe.php?url=https://example.com/page
    
  3. Embed the Proxy URL in your Reveal.js presentation iframe:
    <iframe src="https://yourserver.com/iframe.php?url=https://example.com/page" width="800" height="600"></iframe>

Requirements

  • Web Server with PHP Support: The script needs to be hosted on a web server capable of running PHP (e.g., Apache, Nginx, or similar).
  • PHP 7.0 or Higher: The server must have PHP installed and configured. PHP 5.6 is deprecated and should not be used due to security vulnerabilities.
  • cURL Extension Enabled: Ensure the cURL extension is enabled in the PHP configuration to allow server-side fetching of external content.

Security Considerations

  • Input Validation: Only valid URLs are processed, minimizing the risk of handling malicious input. For better security, consider implementing rate-limiting, logging, or authentication.
  • Legal and Ethical Implications: Be aware that circumventing website security restrictions may breach the terms of service of the target website. Always ensure compliance with relevant policies and laws when using this script.

License

This script is open-source and provided "as is." Feel free to modify and use it for your projects, but be aware of potential legal or ethical implications when bypassing website security restrictions.

<?php
/**
* PHP Proxy Script
*
* This script acts as a proxy to fetch content from a specified URL, bypassing
* restrictive headers (e.g., X-Frame-Options, Content-Security-Policy) and ensuring
* that all linked and dynamically loaded resources are routed through the proxy.
* It rewrites URLs within the fetched content to ensure proper loading and prevents
* issues caused by cross-origin or restrictive security policies.
*
* Author: Christian Prior-Mamulyan
* Email: [email protected]
*/
// Restricting the use of this proxy to prevent misuse
header('X-Frame-Options: SAMEORIGIN');
// Sanitize and validate URL
$url = filter_var($_GET['url'], FILTER_VALIDATE_URL);
if (!$url) {
echo "Invalid URL.";
exit;
}
/**
* Fetches content from a specified URL using cURL.
*
* This function sets up a cURL session to retrieve the content from the specified URL.
* It also ensures that restrictive headers from the original content (e.g., X-Frame-Options,
* Content-Security-Policy) are removed to allow the content to be embedded.
*
* @param string $url The URL to fetch content from.
* @return string The fetched content with headers removed or modified.
*/
function fetch_content($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Follow redirects
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // Verify SSL certificates
curl_setopt($ch, CURLOPT_HEADER, true);
$response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $header_size);
$body = substr($response, $header_size);
curl_close($ch);
// Strip or modify security-related headers
$header_lines = explode("\r\n", $headers);
foreach ($header_lines as $header) {
// Remove or skip over headers that might prevent embedding
if (stripos($header, 'X-Frame-Options') === false && stripos($header, 'Content-Security-Policy') === false) {
header($header);
}
}
return $body;
}
/**
* Rewrites URLs within the content to be proxied through this script.
*
* This function modifies relative and absolute URLs found in the HTML attributes
* (e.g., href, src, action) to ensure they are routed through the proxy. This ensures
* that all content is fetched and displayed correctly.
*
* @param string $content The HTML content in which URLs are to be rewritten.
* @param string $base_url The base URL used to convert relative URLs to absolute.
* @return string The modified content with proxied URLs.
*/
function rewrite_urls($content, $base_url) {
$pattern = '/(href|src|action|url)=[\'"]([^\'"]+)[\'"]/i';
return preg_replace_callback($pattern, function($matches) use ($base_url) {
$attr = $matches[1];
$url = $matches[2];
// Convert relative URL to absolute if needed
if (parse_url($url, PHP_URL_SCHEME) === null) {
$url = rtrim($base_url, '/') . '/' . ltrim($url, '/');
}
// Proxy the URL through this script (even if already absolute)
$proxied_url = 'iframe.php?url=' . urlencode($url);
return $attr . '="' . $proxied_url . '"';
}, $content);
}
/**
* Rewrites JavaScript content to handle dynamic URL creation.
*
* This function modifies JavaScript code that sets URLs using constructs like
* window.location or document.URL, ensuring that dynamically created resources
* are also routed through the proxy.
*
* @param string $content The JavaScript content to modify.
* @param string $base_url The base URL used for proxying dynamic URLs.
* @return string The modified JavaScript content.
*/
function rewrite_js_content($content, $base_url) {
// Replace occurrences of window.location or dynamically created URLs
$content = preg_replace('/window\.location\.href\s*=\s*[\'"]([^\'"]+)[\'"];?/i',
'window.location.href="iframe.php?url=' . urlencode($base_url) . '/$1";',
$content);
$content = preg_replace('/document\.URL\s*=\s*[\'"]([^\'"]+)[\'"];?/i',
'document.URL="iframe.php?url=' . urlencode($base_url) . '/$1";',
$content);
return $content;
}
// Determine content type and apply necessary transformations
$parsed_url = parse_url($url);
$base_url = $parsed_url['scheme'] . '://' . $parsed_url['host'];
$response = fetch_content($url);
$content_type = ''; // Initialize
if (isset($_SERVER["CONTENT_TYPE"])) {
$content_type = strtolower($_SERVER["CONTENT_TYPE"]);
}
// If it's JavaScript, rewrite dynamic URLs
if (stripos($content_type, 'javascript') !== false) {
$response = rewrite_js_content($response, $base_url);
}
// Rewrite URLs in HTML and JavaScript
$rewritten_response = rewrite_urls($response, $base_url);
// Output the modified content
echo $rewritten_response;
?>
@cprima
Copy link
Author

cprima commented Oct 24, 2024

Todo:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment