תוכן מעורב ב-wordpress אחרי מעבר ל-https
נקו אזהרות תוכן מעורב ב-wordpress אחרי מעבר ל-https: אתרו את כתובות ה-http שנשארו במסד הנתונים, החליפו אותן בבטחה, וכפו https בקובץ htaccess.
פורסם
התעודה מותקנת, האתר נטען דרך https, והמנעול עדיין מסרב להופיע. זהו תוכן מעורב: העמוד עצמו הגיע דרך https, אבל משהו בתוכו — תמונה, גיליון סגנון, סקריפט — עדיין מבוקש דרך http:// רגיל. המדריך הזה עובר על איתור הכתובות האלה, החלפתן בלי להשחית נתונים מסודרים, תיקון siteurl ו-home, וכפיית https ברמת השרת כדי שהבעיה לא תוכל לחזור.
מהו תוכן מעורב בעצם
התקנת תעודה משנה את אופן ההצפנה של החיבור. היא אינה משנה את מה שהעמודים שלכם מבקשים. כל http://yoursite.com/wp-content/uploads/logo.png שנכתב לפוסט, לווידג׳ט או להגדרת תבנית לפני המעבר עדיין יושב במסד הנתונים, והדפדפן מבקש אותו בצייתנות דרך חיבור לא מאובטח.
דפדפנים מתייחסים לשתי קטגוריות באופן שונה, וההבחנה חשובה כשאתם מחליטים כמה זה דחוף:
- תוכן מעורב פעיל — סקריפטים, גיליונות סגנון, מסגרות מוטמעות, XHR. נחסמים לחלוטין. זו הסיבה שאתר יכול להיראות שבור אחרי מעבר ל-https בלי שום הודעת שגיאה בשום מקום: גיליון סגנון נדחה בשקט.
- תוכן מעורב סביל — תמונות, אודיו, וידאו. בדרך כלל עדיין נטען, אבל המנעול יורד בדרגה וחלק מהדפדפנים מציגים סימון ״לא מאובטח״.
שניהם ראויים לתיקון. רק הראשון שובר דברים.
שלב 1: גלו מה עדיין לא מאובטח
התחילו בדפדפן. פתחו את העמוד, פתחו את כלי המפתחים, וקראו את המסוף. כל בקשה שנחסמה או ירדה בדרגה מצוינת שם עם הכתובת המלאה שלה. זה אומר לכם מה לא מאובטח; זה לא אומר איפה זה שמור.
לשם כך הביטו ישירות במסד הנתונים. ייצאו אותו וחפשו בקובץ הייצוא:
wp db export dump.sql
grep -o "http://example\.com[^\"']*" dump.sql | sort -u | head -50
אם WP-CLI אינו זמין, mysqldump מייצר את אותו קובץ:
mysqldump -u USER -p DBNAME > dump.sql
קראו את הכתובות הייחודיות שחוזרות. נתיבי העלאות מצביעים על תוכן פוסטים ומטא. נתיבי נכסים של תבנית מצביעים בדרך כלל על אפשרויות. כל דבר עם דומיין שאינכם מזהים הוא הטמעה חיצונית, שדורשת תיקון אחר (מכוסה בהמשך).
שלב 2: תקנו קודם את siteurl ו-home
siteurl ו-home הן שתי האפשרויות ש-wordpress משתמש בהן כדי לבנות כמעט כל כתובת פנימית שהוא מייצר. אם אחת מהן עדיין אומרת http://, wordpress ימשיך לפלוט כתובות לא מאובטחות ולא משנה כמה נקי שאר מסד הנתונים.
בדקו אותן:
wp option get siteurl
wp option get home
או ב-sql:
SELECT option_name, option_value
FROM wp_options
WHERE option_name IN ('siteurl', 'home');
שתי אלה הן מחרוזות פשוטות, לא מערכים מסודרים, ולכן עדכון sql ישיר באמת בטוח כאן:
UPDATE wp_options
SET option_value = REPLACE(option_value, 'http://example.com', 'https://example.com')
WHERE option_name IN ('siteurl', 'home');
מלכודת אחת לפני שתשקיעו בזה זמן. אם wp-config.php מגדיר את WP_HOME או WP_SITEURL, הקבועים האלה עוקפים את מסד הנתונים לחלוטין והעדכון שלכם ייראה כאילו לא עשה דבר:
define( 'WP_HOME', 'https://example.com' );
define( 'WP_SITEURL', 'https://example.com' );
עדכנו אותם שם, או הסירו אותם ותנו למסד הנתונים להוביל. בדקו את זה קודם — זה מסביר לא מעט מקרים של ״שיניתי ושום דבר לא קרה״.
שלב 3: ההחלפה חייבת להיות בטוחה לסידור
כל השאר במסד הנתונים הוא המקום שבו יושב הסיכון האמיתי, והוא אינו הסיכון שרוב האנשים מצפים לו. הסכנה אינה שההחלפה תפספס כתובות. הסכנה היא שהיא תצליח ברמת הטקסט ותשמיד את הנתונים סביבה.
wordpress שומר מערכים ואובייקטים כמחרוזות מסודרות בפורמט php, והפורמט הזה רושם את אורך הבתים של כל מחרוזת שהוא מכיל:
a:1:{s:4:"logo";s:38:"http://example.com/img/logo.png";}
שנו את http:// ל-https:// עם REPLACE גולמי ב-sql, והטקסט יתארך בבית אחד בזמן שהאורך המוצהר נשאר בערך הישן. php קורא את האורך, צועד את מספר הבתים הזה קדימה, לא מוצא את סימן הסיום היכן שהוא מצפה לו, ומסרב לפענח את סידור המערך כולו. אז wordpress מוסר לתבנית או לתוסף ערך שמתנהג כאילו ההגדרה מעולם לא נשמרה.
התסמין אינו שגיאה. התסמין הוא ווידג׳טים שנעלמים, הגדרות מתאם שמתאפסות, ופריסות של בונה עמודים שמוצגות ריקות — בלי ששום דבר בממשק הניהול יעיד שמשהו השתבש. התאוששות מזה בלי גיבוי כואבת באמת, אז קחו אחד:
wp db export backup-before-https-replace.sql
אחר כך השתמשו בכלי שמפענח את הסידור, מחליף בתוך המבנה המפוענח, ומסדר מחדש עם אורכים מתוקנים. הריצו קודם הרצה יבשה:
wp search-replace 'http://example.com' 'https://example.com' --dry-run --all-tables --skip-columns=guid
קראו את הדוח. אם טבלה שאינכם מזהים מציגה אלפי תוצאות, עצרו והביטו לפני שאתם מבצעים. אחר כך הריצו באמת:
wp search-replace 'http://example.com' 'https://example.com' --all-tables --skip-columns=guid --report-changed-only
--skip-columns=guid חשוב: ה-guid הוא מזהה קבוע עבור קוראי הזנות, לא כתובת חיה, וכתיבה מחדש שלו עלולה לגרום למנויים לראות את כל הארכיון שלכם כפוסטים חדשים. אם אתם צריכים לראות אילו עמודות בטוחות ל-sql פשוט ואילו דורשות טיפול מודע לסידור לפני שאתם מריצים משהו, בנו את הפקודות עם כלי החיפוש וההחלפה sql של wordpress.
אם אינכם יכולים להשתמש בשורת הפקודה, תוסף הגירה שמצהיר במפורש שהוא מטפל בנתונים מסודרים מבצע את אותה עבודת פענוח דרך מסך הניהול. אם כלי אינו אומר זאת, הניחו שהוא אינו עושה זאת.
שלב 4: כפו https ברמת השרת
ניקוי מסד הנתונים מונע מהעמודים שלכם לבקש משאבים לא מאובטחים. הוא אינו מונע מגולש להגיע דרך http:// מלכתחילה. זו הפניה ברמת השרת, ומקומה ב-Apache הוא בקובץ .htaccess:
# BEGIN Force HTTPS
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
# END Force HTTPS
שני דברים לגבי המיקום. שימו את זה מעל סמני # BEGIN WordPress — כל מה שבתוכם מושלך בכל פעם שמישהו שומר קישורים קבועים. וזה עובד רק אם mod_rewrite מופעל והמארח הווירטואלי מתיר עקיפות (AllowOverride All, או לפחות FileInfo). ב-nginx מתעלמים מ-.htaccess לגמרי וזה צריך להיכנס לבלוק שרת במקום.
כלל RedirectMatch לא יבצע את העבודה הזו. הוא מתאים לפי נתיב הבקשה בלבד ואין לו דרך לבדוק אם הבקשה הנוכחית כבר מאובטחת, ולכן הוא מפנה בקשות https אל עצמן. ה-RewriteRule המותנה שלמעלה הוא הכלי הנכון.
לולאת ההפניות, ולמה היא קורית
אם האתר מתחיל להפנות עד אינסוף ברגע שאתם מוסיפים את הכלל הזה, ה-TLS שלכם מסתיים אי שם במעלה הזרם — מאזן עומסים, שרת מתווך הפוך, או רשת הפצת תוכן — שמעביר אחר כך http רגיל ל-Apache. Apache רואה בקשה לא מאובטחת, מפנה ל-https, המתווך מעביר שוב http, וכך זה מסתובב.
בדקו במקום זאת את הכותר המועבר:
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
ל-wordpress עצמו יש את אותו שטח מת בהגדרה הזו — is_ssl() קורא את $_SERVER['HTTPS'], שהמתווך לעולם אינו מגדיר, ולכן כתובות הניהול יוצאות כ-http://. הוסיפו את זה ל-wp-config.php, מעל השורה ״הפסיקו לערוך״:
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
$_SERVER['HTTPS'] = 'on';
}
כדאי להיות ישרים לגבי הסיכון: X-Forwarded-Proto הוא כותר שמסופק על ידי הלקוח. אמון בו נכון רק כאשר מתווך שבשליטתכם תמיד דורס אותו. בשרת שנגיש ישירות מהאינטרנט, אפשר לזייף אותו.
מה שהחלפה במסד הנתונים לא תתקן
- כתובות מקודדות בקבצים. כל דבר שנכתב לתוך
functions.php, לתבנית של ערכת בת, או כנתיב נכס מוטמע אינו נמצא במסד הנתונים. הריצו grep על תיקיית התבנית בנפרד. - JSON עם תווי בריחה. חלק מהבונים שומרים כתובות בצורה
https:\/\/example.com. חיפוש הצורה הרגילה מפספס אותן לחלוטין, ולכן ייתכן שיידרש מעבר שני על המחרוזת עם תווי הבריחה. - משאבים חיצוניים. סקריפט או הטמעה של צד שלישי שזמינים רק דרך http אינם ניתנים לתיקון מהצד שלכם. מצאו גרסת https או ותרו עליהם.
- מטמונים. מטמון עמודים, מטמון אובייקטים ועותקי רשת הפצת התוכן ממשיכים להגיש את הסימון הישן גם אחרי החלפה תקינה. רוקנו את שלושתם לפני שתסיקו שההחלפה נכשלה.
דבר אחד שכדאי לדלג עליו: כותר מדיניות אבטחת התוכן upgrade-insecure-requests ישתיק את האזהרות בכך שיכתוב מחדש בקשות לא מאובטחות בדפדפן. אבל הוא מטפל בתסמין ומשאיר את הכתובות השגויות במסד הנתונים שלכם, שם הייצוא, ההגירה או ההזנה הבאים ייקחו אותן איתם הלאה. תקנו את הנתונים, ואז השתמשו בו כרשת ביטחון אם תרצו.
עדיין תקועים?
בדקו מחדש את siteurl ו-home אחרי כל שלב — תוספים וכלי הגירה לפעמים כותבים אותם מחדש מאחורי הגב שלכם. אם המסוף עדיין מציין כתובת לא מאובטחת שאינכם מוצאים בקובץ הייצוא, הציגו את מקור העמוד וחפשו אותה שם: אם היא מופיעה בסימון המיוצר אך לא במסד הנתונים, היא נבנית ב-php, והתבנית או התוסף שמייצרים אותה הם הדבר שצריך לתקן.
FAQ
שאלות
למה אתר ה-wordpress שלי עדיין מציג אזהרות תוכן מעורב אחרי התקנת תעודת SSL?
התעודה משנה רק את אופן ההצפנה של החיבור, לא את מה שהעמודים שלכם מבקשים. כתובות http ישנות נשארות שמורות במסד הנתונים, בתוך תוכן הפוסטים, הגדרות הווידג׳טים והגדרות התבנית. הדפדפן טוען את העמוד דרך https, רואה תמונה או סקריפט שמבוקשים דרך http רגיל, ומדווח על תוכן מעורב בעמוד שמכל בחינה אחרת מאובטח.
איך מאתרים את כתובות ה-http שעדיין נמצאות במסד הנתונים של wordpress?
פתחו עמוד בדפדפן וקראו את מסוף המפתחים, שמציין כל בקשה לא מאובטחת לפי הכתובת שלה. אחר כך ייצאו את מסד הנתונים וחפשו בקובץ הייצוא את הדומיין שלכם עם הקידומת http. ספירת התוצאות בכל טבלה מגלה אם הבעיה יושבת בתוכן הפוסטים, ב-wp_options, או בטבלאות של תוספים שלא ציפיתם להן.
אפשר לתקן תוכן מעורב עם חיפוש והחלפה פשוטים ב-sql?
רק לערכים פשוטים כמו siteurl ו-home. כל דבר ש-wordpress שומר כמערך מסודרת, וזה כולל את רוב ערכי האפשרויות והמטא, רושם את אורך הבתים של כל מחרוזת בתוכו. החלפה גולמית משנה את הטקסט אך משאירה את האורך הישן, ואז הערך נכשל בפענוח הסידור וההגדרה חוזרת בשקט לברירת המחדל.
איזה כלל ב-htaccess כופה https ב-wordpress?
כלל RewriteRule שמוגן בתנאי על משתנה https, וממוקם מעל סמני BEGIN WordPress כדי ששמירת הקישורים הקבועים לא תמחק אותו. מאחורי שרת מתווך או רשת הפצת תוכן משתנה https נקרא ככבוי גם בבקשות מאובטחות, ולכן בדקו במקום זאת את הכותר X-Forwarded-Proto או שהכלל יפנה עד אינסוף.
למה האתר שלי נכנס ללולאת הפניות אחרי שכפיתי https?
כמעט בוודאות ה-TLS שלכם מסתיים בשרת מתווך או ברשת הפצת תוכן, שמעביר אחר כך http רגיל ל-Apache. כלל הכתיבה מחדש רואה בקשה לא מאובטחת, מפנה ל-https, המתווך מעביר שוב http, והלולאה חוזרת. החליפו את התנאי לכותר X-Forwarded-Proto והגדירו את משתנה השרת https בקובץ wp-config.
האם תוכן מעורב שובר את כל העמוד או רק את המנעול?
תלוי במשאב. דפדפנים חוסמים לחלוטין תוכן מעורב פעיל כמו סקריפטים, גיליונות סגנון ומסגרות מוטמעות, וזה עלול לשבור פריסה או פונקציונליות בלי שום הסבר גלוי. תוכן מעורב סביל כמו תמונות ווידאו בדרך כלל עדיין נטען, אבל המנעול יורד בדרגה והגולשים עשויים לראות סימון ׳לא מאובטח׳. שניהם ראויים לתיקון.