[{"data":1,"prerenderedAt":923},["ShallowReactive",2],{"blog-uk-move-a-secret-to-an-edge-function":3,"blog-index-uk":571},{"id":4,"title":5,"body":6,"category":526,"cover":527,"coverAlt":528,"description":529,"draft":530,"extension":531,"faq":532,"image":549,"keywords":550,"meta":559,"navigation":560,"ogTitle":561,"path":562,"published":563,"seo":564,"stem":565,"tldr":566,"updated":563,"__hash__":570},"blog_uk\u002Fblog\u002Fmove-a-secret-to-an-edge-function.md","Сховати ключ API: перенесіть його в Supabase Edge Function",{"type":7,"value":8,"toc":512},"minimark",[9,13,29,32,37,40,53,56,62,66,69,72,80,84,87,162,171,201,221,225,228,244,247,257,263,268,272,275,282,292,313,316,320,323,346,349,353,356,359,377,380,387,391,394,407,410,418,427,431,434,452,458,471,475,504],[10,11,12],"p",{},"Кожна інструкція про витік ключа API завершується в одному й тому самому місці:\nперенесіть його на сервер. А далі обривається. У вас лишається застосунок,\nзібраний у Lovable, Bolt чи Cursor, жодного сервера навколо та речення, яке\nприпускає, що ви вже знаєте, що робити далі.",[10,14,15,16,20,21,28],{},"Ось та частина, яку інструкція за інструкцією лишає поза кадром. ",[17,18,19],"strong",{},"Перенесення\nключа в Supabase Edge Function прибирає його з вашої сторінки, і саме собою це\nне заважає чужій людині ним скористатися."," Власна документація Supabase пояснює\nчому: перевірка, яку розгорнута function виконує за замовчуванням,\n",[22,23,27],"a",{"href":24,"rel":25},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ffunctions\u002Fauth-headers",[26],"nofollow","приймає також ваш публічний ключ",",\nа ваш публічний ключ лежить у вашому фронтенді, доступний для копіювання будь-кому.\nСховати ключ це проста половина. Про другу половину не пише ніхто: вирішити,\nкому ваша нова function відповідає.",[10,30,31],{},"Уявіть ключ як універсальний ключ від складу. Зараз він приклеєний зсередини до\nвітрини, де його читає кожен, хто зупиниться. Edge Function це підсобка з\nвіконцем видачі: ключ лягає туди, а відвідувачі просять у віконці замість того,\nщоб заходити й брати самим. Чи це покращення, залежить від того, кому віконце\nвідчиняється.",[33,34,36],"h2",{"id":35},"куди-покласти-ключ-api-якщо-не-у-фронтенд","Куди покласти ключ API, якщо не у фронтенд?",[10,38,39],{},"Будь-куди, де немає браузера. Edge Function це найменший варіант такого місця.",[10,41,42,43,47,48,52],{},"Браузер не вміє тримати таємницю. Усе, що потрібно вашій сторінці для роботи,\nзавантажує кожен відвідувач, і відвідувач може прочитати все: код, зображення,\nзначення, вкомпільовані в код. Це не вада вашого конструктора. Це те, чим є\nвебсторінка.\n",[22,44,46],{"href":45},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Які ключі API безпечні у фронтенді","\nце довга версія; коротка полягає в тому, що ключ ",[49,50,51],"code",{},"sk_",", ключ OpenAI або\nсекретний ключ Supabase ніколи б не пережив подорожі в браузер.",[10,54,55],{},"Supabase Edge Function це невеликий шматок коду, який виконується на машинах\nSupabase. Вона може читати секрети, які ви задали у проєкті, відповідає за\nвласною веб-адресою, і ваш застосунок викликає її на імʼя. Ви пишете один файл,\nSupabase його запускає, і немає сервера, який треба орендувати, латати чи\nтримати ввімкненим.",[57,58],"diagram",{"alt":59,"caption":60,"src":61},"Два варіанти. Угорі ключ лежить усередині бандла, який завантажує кожен відвідувач, і браузер звертається до постачальника напряму. Унизу бандл не несе ключа, браузер викликає Edge Function, а function тримає ключ і звертається до постачальника.","Угорі: ключ лежить у файлі, який завантажує кожен відвідувач, тож він є в кожного відвідувача. Унизу: браузер питає function, а ключ ніколи не залишає Supabase.","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fwhere-the-key-lives-1600x800.png",[33,63,65],{"id":64},"замініть-уже-опублікований-ключ-перш-ніж-щось-переносити","Замініть уже опублікований ключ, перш ніж щось переносити",[10,67,68],{},"Ключ, який сьогодні лежить у вашому фронтенді, уже публічний, і лишається таким\nпісля того, як ви приберете його з коду.",[10,70,71],{},"Кожен відвідувач, який відкривав ваш сайт, його завантажив. Кожен робот теж, і\nавтоматичні роботи обходять увесь веб у пошуках саме таких рядків. Ваш старий\nбандл до того ж лишається у вашій історії версій і в кожному кеші, де є копія\nвашої сторінки. Видалення рядка з файлу, яким ви керуєте, нічого не міняє у\nзначенні, яке вже роздали.",[10,73,74,75,79],{},"Тож порядок такий: створити новий ключ у постачальника, притримати його хвилину\nта відкликати старий, щойно function нижче запрацює. Потім перегляньте сторінку\nрахунків і журнали використання за весь період, коли старий ключ був назовні.\nЗаміна зупиняє те, що буде далі; на те, що вже сталося, вона не впливає. Якщо це\nбув секретний ключ Supabase, ",[22,76,78],{"href":77},"\u002Fblog\u002Frotate-supabase-service-role-key","порядок\nроботи"," має нюанс, який варто прочитати\nзаздалегідь.",[33,81,83],{"id":82},"чотири-кроки","Чотири кроки",[10,85,86],{},"Зберегти секрет, написати function, розгорнути її, а потім змінити застосунок,\nщоб він викликав function замість постачальника.",[88,89,90,106],"table",{},[91,92,93],"thead",{},[94,95,96,100,103],"tr",{},[97,98,99],"th",{},"Крок",[97,101,102],{},"У командному рядку",[97,104,105],{},"У панелі",[107,108,109,123,136,149],"tbody",{},[94,110,111,115,120],{},[112,113,114],"td",{},"1. Зберегти секрет",[112,116,117],{},[49,118,119],{},"supabase secrets set MY_API_KEY=…",[112,121,122],{},"Edge Functions → Secrets, далі Key і Value",[94,124,125,128,133],{},[112,126,127],{},"2. Написати function",[112,129,130],{},[49,131,132],{},"supabase functions new forward-request",[112,134,135],{},"Edge Functions → Deploy a new function → Via Editor",[94,137,138,141,146],{},[112,139,140],{},"3. Розгорнути",[112,142,143],{},[49,144,145],{},"supabase functions deploy",[112,147,148],{},"Кнопка Deploy під редактором",[94,150,151,154,159],{},[112,152,153],{},"4. Викликати із застосунку",[112,155,156],{},[49,157,158],{},"supabase.functions.invoke('…')",[112,160,161],{},"Так само, у коді вашого застосунку",[10,163,164,165,170],{},"Усередині function секрет приходить як змінна середовища, тобто іменоване\nзначення, яке код може прочитати, а ніхто ззовні не може. Документація Supabase\nпро\n",[22,166,169],{"href":167,"rel":168},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ffunctions\u002Fsecrets",[26],"секрети Edge Functions"," має\nповний довідник, і три деталі в ній економлять годину плутанини:",[172,173,174,185,191],"ul",{},[175,176,177,184],"li",{},[17,178,179,180,183],{},"Імʼя секрету не може починатися з ",[49,181,182],{},"SUPABASE_","."," Цей префікс зарезервовано\nдля значень, які Supabase задає за вас, і його відхиляють і панель, і API.",[175,186,187,190],{},[17,188,189],{},"Новий секрет читається одразу."," Після його зміни розгортати function\nнаново не потрібно.",[175,192,193,196,197,200],{},[17,194,195],{},"Локальне та робоче середовища розділені."," Локальний стек читає\n",[49,198,199],{},"supabase\u002Ffunctions\u002F.env",", а це інше місце, ніж секрети вашого робочого\nпроєкту, тож задайте значення в обох, інакше function працює на вашій машині й\nпадає після розгортання.",[10,202,203,204,207,208,211,212,215,216,220],{},"Далі видаліть стару змінну з фронтенду. Якщо вона звалася ",[49,205,206],{},"VITE_",",\n",[49,209,210],{},"NEXT_PUBLIC_"," чи ",[49,213,214],{},"EXPO_PUBLIC_",", цей префікс був вказівкою вкомпілювати значення\nв бандл, і ",[22,217,219],{"href":218},"\u002Fblog\u002Fvite-and-next-public-env-vars","префікс це вся\nісторія"," того, як воно туди потрапило.",[33,222,224],{"id":223},"чи-означає-вимога-токена-що-викликати-можуть-лише-мої-користувачі","Чи означає вимога токена, що викликати можуть лише мої користувачі?",[10,226,227],{},"Ні, і це те місце статті, яке варто прочитати двічі.",[10,229,230,231,234,235,238,239,243],{},"Supabase вмикає за замовчуванням перевірку під назвою ",[49,232,233],{},"verify_jwt",". Вона\nдивиться на заголовок ",[49,236,237],{},"Authorization"," до того, як запуститься ваш код, і\nвідхиляє запит, якщо там немає нічого дійсного. Звучить як двері, які відчиняють\nлише ваші користувачі. Це не так, бо Supabase документує й те, що та сама\nперевірка\n",[22,240,242],{"href":24,"rel":241},[26],"приймає публічний або секретний ключ","\nу будь-якому з двох заголовків, задля сумісності зі старішими проєктами, і прямо\nдодає, що сама по собі перевірка не автентифікує того, хто надсилає лише ключ\nAPI.",[10,245,246],{},"Ваш публічний ключ лежить у вашому фронтенді. Це правильно, і так задумано. Але\nце також означає, що той, хто відкриє ваш сайт, прочитає ключ і надішле його\nвашій новій function, пройде платформну перевірку та потрапить у ваш код.",[248,249,251],"callout",{"type":250},"warn",[10,252,253,256],{},[17,254,255],{},"Ось так перенесений ключ стає відкритим проксі."," Ключа вже немає на вашій\nсторінці, тож сканер, який шукає рядки у формі ключа, нічого не знаходить, а\nрахунок від OpenAI чи Stripe далі зростає. Змінилося те, що тепер запити йдуть\nчерез вас. Раніше чужа людина мала ваш ключ; тепер чужа людина має вашу\nвеб-адресу, яка використовує ваш ключ замість неї, без обмеження на кількість\nразів.",[10,258,259,260,262],{},"На складі ",[49,261,233],{}," це вахтер, який перевіряє, чи є у вас перепустка\nвідвідувача. Вона є в кожного відвідувача, бо ви самі роздаєте їх на вході.\nЛюдина біля віконця робить іншу роботу, і саме вона питає, який саме ви\nвідвідувач.",[57,264],{"alt":265,"caption":266,"src":267},"Двоє звертаються до однієї Edge Function. Чужа людина, яка надсилає лише публічний ключ, проходить платформну перевірку verify_jwt, а потім її відхиляє перевірка всередині function. Авторизований користувач із токеном сесії проходить обидві та дістається API постачальника.","Обидва проходять платформну перевірку. Лише другий проходить перевірку того, хто викликає, і саме цю другу вам треба додати.","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Ftwo-checks-1600x860.png",[33,269,271],{"id":270},"замкнути-function-щоб-не-вийшов-відкритий-проксі","Замкнути function, щоб не вийшов відкритий проксі",[10,273,274],{},"Вирішіть, кого ваша function приймає, і запишіть це рішення всередину function.",[10,276,277,278,281],{},"Supabase дає для цього обгортку, тож це один рядок, а не проєкт. Поставте\n",[49,279,280],{},"auth: 'user'",", і function прийматиме токен авторизованого користувача та\nвіддасть вашому коду клієнт бази, уже обмежений правилами Row Level Security\nцього користувача:",[283,284,290],"pre",{"className":285,"code":287,"language":288,"meta":289},[286],"language-ts","import { withSupabase } from 'npm:@supabase\u002Fserver@1'\n\nexport default {\n  fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => {\n    \u002F\u002F ctx.userClaims каже, хто викликає. Відхиляйте тут те, чого не хочете,\n    \u002F\u002F а потім звертайтеся до постачальника із секретом із середовища.\n    return Response.json({ ok: true })\n  }),\n}\n","ts","",[49,291,287],{"__ignoreMap":289},[10,293,294,295,300,301,304,305,308,309,312],{},"Сторінка ",[22,296,299],{"href":297,"rel":298},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ffunctions\u002Fauth",[26],"Securing Edge\nFunctions"," перелічує інші\nрежими, і два з них важливі для звичайного застосунку. Function, яку викликає\nінша машина, а не браузер, бере ",[49,302,303],{},"auth: 'secret'"," із секретним ключем у заголовку\n",[49,306,307],{},"apikey",". Function, яка приймає вебхуки від Stripe чи GitHub, не може взяти\nжодного з них, бо ці постачальники не мають вашого токена; вона ставить\n",[49,310,311],{},"verify_jwt = false"," і перевіряє підпис постачальника всередині обробника.",[10,314,315],{},"Хай що ви оберете, свідомо вирішіть, що станеться, коли прийде той, кого ви не\nчекали. Приклад function, яка може приймати будь-кого, Supabase наводить такий:\nперевірка стану, а перевірка стану нічого не коштує, коли її викликає чужа\nлюдина. Function, яка переадресовує платний виклик API, виставляє вам рахунок за\nкожен із них.",[33,317,319],{"id":318},"чи-можна-використовувати-service_role-в-edge-function","Чи можна використовувати service_role в Edge Function?",[10,321,322],{},"Можна. Function це єдине місце, де секретному ключу Supabase справді є місце.",[10,324,325,326,329,330,333,334,329,337,340,341,345],{},"Вставляти його теж не доведеться. Supabase кладе ключі проєкту в середовище\nfunction, тож код читає їх звідти, а не з секрету, який ви задали. Новіші\nпроєкти отримують ",[49,327,328],{},"SUPABASE_SECRET_KEYS"," і ",[49,331,332],{},"SUPABASE_PUBLISHABLE_KEYS",", кожен з\nяких це невеликий словник іменованих ключів; старіші проєкти отримують\n",[49,335,336],{},"SUPABASE_SERVICE_ROLE_KEY",[49,338,339],{},"SUPABASE_ANON_KEY"," під їхніми початковими\nназвами. ",[22,342,344],{"href":343},"\u002Fblog\u002Fsupabase-new-api-keys","Що змінилося, коли Supabase перейменував\nключі"," підкаже, яка пара у вас.",[10,347,348],{},"Беріть секретний ключ для роботи, якій справді треба бачити кожен рядок,\nнаприклад для запису в журнал, який користувач не має права редагувати. Для\nвсього, що користувач читає про себе, беріть його власний токен і дайте вашим\nправилам Row Level Security відфільтрувати, бо саме для цього вони є.",[33,350,352],{"id":351},"перевірка-з-браузера-єдиний-справжній-доказ","Перевірка з браузера, єдиний справжній доказ",[10,354,355],{},"Відкрийте свій робочий сайт, відкрийте вкладку мережі й подивіться, що браузер\nнадсилає насправді.",[10,357,358],{},"Дві речі для перевірки:",[172,360,361,371],{},[175,362,363,366,367,370],{},[17,364,365],{},"Жоден запит не несе ключа."," Пройдіть ту частину застосунку, яка раніше\nзверталася до постачальника. Вихідний запит має йти на\n",[49,368,369],{},"…supabase.co\u002Ffunctions\u002Fv1\u002Fваша-function",", і єдиним посвідченням у ньому має\nбути ваш публічний ключ або токен вашого користувача.",[175,372,373,376],{},[17,374,375],{},"Ключа немає в завантаженому коді."," Скористайтеся пошуком браузера по всіх\nзавантажених файлах і вставте перший десяток символів старого ключа. Жодного\nрезультату це та відповідь, якої ви хочете.",[10,378,379],{},"Лише нова збірка й нове розгортання прибирають значення з бандла. Тож ключ, який\nдосі знаходиться в пошуку, зазвичай означає, що фронтенд пішов раніше, ніж із\nнього прибрали змінну.",[10,381,382,383,183],{},"Наше безкоштовне сканування робить другу перевірку ззовні й називає те, що може\nпрочитати у вашому робочому бандлі, зокрема який ключ Supabase ви опублікували.\nВоно триває близько 20 секунд і не потребує облікового запису:\n",[22,384,386],{"href":385},"\u002Fsecurity-scanner","просканувати застосунок",[33,388,390],{"id":389},"як-зробити-це-з-lovable-bolt-чи-replit","Як зробити це з Lovable, Bolt чи Replit",[10,392,393],{},"Скористайтеся панеллю Supabase. Жодного кроку в терміналі там немає.",[10,395,396,397,400,401,406],{},"Відкрийте проєкт, оберіть Edge Functions на бічній панелі, далі ",[17,398,399],{},"Deploy a new\nfunction → Via Editor",". ",[22,402,405],{"href":403,"rel":404},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ffunctions\u002Fquickstart-dashboard",[26],"Швидкий старт у\nпанелі"," від\nSupabase проходить це зі знімками екрана, а серед запропонованих шаблонів є один\nдля переадресації до постачальника ШІ, тобто саме та форма цієї роботи.\nРозгортання триває від десяти до тридцяти секунд, і далі function працює за\nвласною адресою. Ваш секрет кладеться на сторінку Edge Function Secrets, у тому\nж розділі.",[10,408,409],{},"Одне застереження, яке варто знати, перш ніж на це покладатися: Supabase пише,\nщо редактор у панелі не має контролю версій, самих версій і відкату, і радить\nйого для швидкої роботи, а не для коду, який має лишитися. Натискання Deploy\nперезаписує те, що було. Якщо function зрештою робить щось важливе для вас,\nзавантажте її з тієї сторінки й збережіть файл.",[10,411,412,413,417],{},"Є також версія цього питання у формі Replit, бо Replit має власне сховище\nсекретів, а ваш застосунок запускає там власний сервер. ",[22,414,416],{"href":415},"\u002Fblog\u002Freplit-secrets-explained","Що насправді роблять\nReplit Secrets"," це та версія.",[248,419,421],{"type":420},"note",[10,422,423,426],{},[17,424,425],{},"Якщо виклик іде з браузера, function потрібні заголовки CORS."," Браузер не дає\nвашій сторінці прочитати відповідь з іншої адреси, доки ця адреса цього не\nдозволить. Шаблони в панелі Supabase несуть ці заголовки; написана з нуля\nfunction їх не має, і симптом це запит, який у журналах function виглядає\nнормально, а у вашому застосунку падає.",[33,428,430],{"id":429},"коли-edge-function-це-неправильна-відповідь","Коли Edge Function це неправильна відповідь",[10,432,433],{},"Два випадки, і в обох перенесення коштує роботи й не дає нічого.",[10,435,436,439,440,443,444,447,448,451],{},[17,437,438],{},"Ключ був публічним за задумом."," Ключ Stripe ",[49,441,442],{},"pk_live_",", публічний ключ\nSupabase або ключ ",[49,445,446],{},"anon",", публічний токен Mapbox: вони створені жити в браузері,\nа захист міститься деінде. Якщо покласти такий за function, додається гак і не\nприбирається жоден ризик. ",[22,449,450],{"href":45},"Які це\nключі"," це той перелік.",[10,453,454,457],{},[17,455,456],{},"Ключ можна обмежити вашим власним сайтом."," Браузерні ключі Google це\nзвичайний приклад: у консолі Google ви обмежуєте такий ключ своїми доменами, і\nсаме це рішення Google передбачає для цього випадку. Ключ лишається читабельним\nі перестає бути корисним тому, хто його скопіює.",[10,459,460,461,465,466,470],{},"Усе інше має бути на сервері. У ключа OpenAI чи Anthropic публічного варіанта\nнемає, і тому ",[22,462,464],{"href":463},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","ключ постачальника ШІ у вашому\nфронтенді"," не має налаштування, яке\nйого врятує, і жодна мініфікація не сховає ",[22,467,469],{"href":468},"\u002Fblog\u002Fstripe-secret-key-in-frontend","секретний ключ\nStripe"," від того, хто читає вашу сторінку.",[33,472,474],{"id":473},"що-зробити-просто-зараз","Що зробити просто зараз",[476,477,478],"key-takeaways",{},[172,479,480,483,489,492,498,501],{},[175,481,482],{},"Спершу замініть ключ. Створіть новий у постачальника, покладіть його в секрет function і відкличте старий, щойно function запрацює.",[175,484,485,486,488],{},"Зберігайте секрет у своєму проєкті Supabase, а не в репозиторії й не у змінній ",[49,487,206],{},". Задайте його окремо для локальної розробки та для робочого середовища.",[175,490,491],{},"Розгорніть function, яка використовує секрет, і змініть застосунок так, щоб він викликав function на імʼя замість постачальника.",[175,493,494,495,497],{},"Додайте перевірку того, хто викликає. Сам по собі ",[49,496,233],{}," приймає публічний ключ із вашого ж фронтенду, тож чужу людину він не спиняє.",[175,499,500],{},"Видаліть стару змінну, зберіть наново й переконайтеся у вкладці мережі браузера, що нічого вихідне не несе ключа.",[175,502,503],{},"Перегляньте рахунки та використання за весь період, коли старий ключ був публічним. Заміна спиняє наступне списання, а не останнє.",[10,505,506,507,511],{},"Якщо вам зручніше пройтися всім застосунком, а не одним ключем,\n",[22,508,510],{"href":509},"\u002Fchecklist","десятихвилинний чеклист безпеки"," охоплює це разом з іншим, що варто\nзакрити у щойно запущеному застосунку.",{"title":289,"searchDepth":513,"depth":513,"links":514},3,[515,517,518,519,520,521,522,523,524,525],{"id":35,"depth":516,"text":36},2,{"id":64,"depth":516,"text":65},{"id":82,"depth":516,"text":83},{"id":223,"depth":516,"text":224},{"id":270,"depth":516,"text":271},{"id":318,"depth":516,"text":319},{"id":351,"depth":516,"text":352},{"id":389,"depth":516,"text":390},{"id":429,"depth":516,"text":430},{"id":473,"depth":516,"text":474},"Основи безпеки","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcover-1200x630.png","Аркуш із отвором у формі ключа, а за ним запечатана скриня із закритим замком і ключем, видимим крізь невелике віконце.","Сховати ключ API означає прибрати його з браузера, а Supabase Edge Function це найменше місце, куди його покласти. Два кроки поруч важать більше.",false,"md",[533,535,538,541,544,546],{"q":36,"a":534},"Будь-куди, де немає браузера. Supabase Edge Function це найменший варіант: ви зберігаєте ключ як секрет у своєму проєкті, пишете невеликий файл, який його використовує, а ваш застосунок викликає цю function на імʼя замість того, щоб звертатися до постачальника напряму. Так само працюють serverless-маршрут у вашого хостера або власний сервер. Спільне в них те, що ключ читається там, де ваш відвідувач його не бачить.",{"q":536,"a":537},"Що таке Supabase Edge Function?","Невеликий шматок коду, який виконується на машинах Supabase, а не в браузері вашого відвідувача. Він відповідає за власною веб-адресою, він може читати секрети, які ви задали у проєкті, і ваш застосунок викликає його через supabase.functions.invoke. Ви пишете один файл, Supabase його запускає, і немає жодного сервера, який треба орендувати чи обслуговувати.",{"q":539,"a":540},"Чи треба замінювати ключ після перенесення?","Так, і зробіть це першим. Ключ, який лежав у вашому фронтенді, завантажив кожен відвідувач і кожен робот, що читав ваш сайт, і прибирання його з коду нічого не міняє в тих копіях. Створіть новий ключ у постачальника, покладіть його в секрет своєї Edge Function і відкличте старий. Потім перегляньте рахунки та використання за весь період, коли старий ключ діяв.",{"q":542,"a":543},"Чи може будь-хто викликати мою Edge Function?","За замовчуванням function відхиляє запит узагалі без токена, але ця перевірка слабша, ніж здається. Supabase документує, що платформна перевірка приймає також ваш публічний або секретний ключ, а ваш публічний ключ лежить у вашому фронтенді, де його може прочитати будь-хто. Тобто перевірка зупиняє порожній запит, а не рішучий. Щоб приймати лише ваших авторизованих користувачів, перевіряйте того, хто викликає, усередині function.",{"q":319,"a":545},"Можна. Edge Function це єдине місце, де секретному ключу Supabase справді є місце, і Supabase сам кладе ключі проєкту в середовище function, тож вам ніколи не доводиться його вставляти. Беріть його для роботи, яка має бачити кожен рядок, а для всього, що має дотримуватися ваших правил Row Level Security, беріть токен того, хто викликає.",{"q":547,"a":548},"Чи можна зробити це без термінала?","Можна. У панелі Supabase є розділ Edge Functions, де ви пишете function у браузері, тиснете Deploy і задаєте свій секрет на сторінці Edge Function Secrets. Supabase попереджає, що редактор у панелі не веде історії версій, тож радить його для швидкої роботи, а командний рядок для того, що ви плануєте зберегти.","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",[551,552,553,554,555,556,557,558],"сховати ключ api supabase edge function","supabase edge function secrets","supabase secrets set","перенести ключ api на бекенд","викликати openai з edge function","тримати ключ api поза фронтендом","змінні середовища supabase edge function","куди покласти секретний ключ",{},true,"Сховати ключ API у Supabase Edge Function","\u002Fblog\u002Fmove-a-secret-to-an-edge-function","2026-10-05",{"title":5,"description":529},"blog\u002Fmove-a-secret-to-an-edge-function",[567,568,569],"Ніщо в браузері не вміє тримати таємницю, тож сховати ключ API означає перенести його туди, де це можливо. Supabase Edge Function це найменший сервер, який ви можете мати.","Перенесення це чотири кроки. Спершу замініть ключ, який ви вже опублікували, бо копія у вашому старому бандлі лишається читабельною й після того, як ви приберете його звідти.","Розгорнута function за замовчуванням вимагає токен, і публічний ключ із вашого ж фронтенду цю вимогу задовольняє. Перевірка того, хто саме викликає, це окремий крок, і саме він не дає чужій людині витрачати вашу квоту.","1960_Hi3SAg8LXZc2iG7vTZPwT_RCF6UhF6FHPFZYHk",[572,578,584,590,596,602,608,609,615,621,627,633,639,645,652,658,664,669,675,681,687,693,699,705,710,715,721,727,733,739,745,751,757,763,769,774,780,786,792,798,803,809,815,820,826,832,838,844,850,856,862,868,874,880,886,891,896,902,908,913,919],{"path":573,"title":574,"description":575,"published":576,"category":526,"image":577,"draft":530},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" при вивантаженні","\"New row violates row-level security policy for table objects\" означає, що вашому вивантаженню бракує правила insert. Публічний бакет його не додає.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":579,"title":580,"description":581,"published":582,"category":526,"image":583,"draft":530},"\u002Fblog\u002Fbase44-security-scan","Сканування безпеки Base44: те, що бачить лише воно","Сканування безпеки Base44 перевіряє сім видів проблем зсередини. Ось половина, яку читає тільки воно, і половина, на яку воно ніколи не дивиться.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":585,"title":586,"description":587,"published":588,"category":526,"image":589,"draft":530},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Ваш API-ключ витік. Порядок дій","API-ключ витік, і ви не знаєте, що робити першим. Не кожен ключ у вашому фронтенді є витоком, а порядок важить більше за швидкість.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":591,"title":592,"description":593,"published":594,"category":526,"image":595,"draft":530},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" без вимкнення RLS","\"Infinite recursion detected in policy for relation\" означає, що ваша policy запитала таблицю, яку вона захищає. Ось як розірвати коло.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":597,"title":598,"description":599,"published":600,"category":526,"image":601,"draft":530},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" у Supabase, і хибне виправлення","\"No API key found in request\" означає, що запит дійшов до Supabase без ключа. Більшість відповідей натомість вказують на правила вашої бази.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":603,"title":604,"description":605,"published":606,"category":526,"image":607,"draft":530},"\u002Fblog\u002Fis-base44-safe","Чи безпечний Base44? Дані 5 442 застосунків","Чи безпечний Base44? Ми прогнали дев’ять перевірок на 5 442 робочих застосунках Base44. Майже всі отримали B з причин, яких власник ніколи не обирав.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":562,"title":5,"description":529,"published":563,"category":526,"image":549,"draft":530},{"path":610,"title":611,"description":612,"published":613,"category":526,"image":614,"draft":530},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Чи відкритий ваш файл .env? Дванадцять шляхів для перевірки","Чи відкритий ваш файл .env на вашому власному вебсервері? Дванадцять адрес скажуть це за хвилину, а влучання означає, що все в ньому вже публічне.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":616,"title":617,"description":618,"published":619,"category":526,"image":620,"draft":530},"\u002Fblog\u002Fis-v0-safe","Безпека v0: усі 1 790 просканованих застосунків v0 отримали A","Безпека v0 на 1 790 живих застосунках v0: усі отримали A. Лише 17 згадували базу даних, і саме це здебільшого вимірює оцінка A.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":622,"title":623,"description":624,"published":625,"category":526,"image":626,"draft":530},"\u002Fblog\u002Fis-bolt-safe","Чи безпечний Bolt? Що показали 1 123 застосунки Bolt","Чи безпечний Bolt? Ми прогнали 1 123 живі застосунки Bolt через дев’ять перевірок. Хостинг був чистим. Знахідки: ключі й відкриті таблиці в самих застосунках.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":628,"title":629,"description":630,"published":631,"category":526,"image":632,"draft":530},"\u002Fblog\u002Fis-supabase-down-or-your-app","Supabase не працює чи проблема у вашому застосунку? Як розрізнити","Supabase не працює чи зламався ваш застосунок? Пауза, повна база й ваша власна помилка виглядають однаково. Чотири перевірки їх розрізняють.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":634,"title":635,"description":636,"published":637,"category":526,"image":638,"draft":530},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","Чи шифрує Supabase мої дані? Так. Ось від чого це захищає","Чи шифрує Supabase дані? Так: AES-256 у стані спокою, TLS під час передавання, SOC 2 та ISO 27001. Що покриває кожне і який витік не зупиняє жодне.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":640,"title":641,"description":642,"published":643,"category":526,"image":644,"draft":530},"\u002Fblog\u002Fsupabase-free-plan-limits","Ліміти безкоштовного тарифу Supabase і що стається на кожному","Ліміти безкоштовного тарифу Supabase: 500 МБ бази, 5 ГБ egress і жодних резервних копій. Що стається на кожній межі і що змінює Pro за $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":646,"title":647,"description":648,"published":649,"category":650,"image":651,"draft":530},"\u002Fblog\u002Ftest-your-supabase-backup","Перевірте резервну копію Supabase до того, як вона знадобиться","Як перевірити резервну копію Supabase: відновити в тестовий проєкт, порахувати рядки, увійти й знайти рядок, якого бракує обрізаному файлу.","2026-09-28","Backups","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":653,"title":654,"description":655,"published":656,"category":650,"image":657,"draft":530},"\u002Fblog\u002Fsupabase-backup-github-action","Безкоштовна резервна копія Supabase через GitHub Action і підступ","Резервна копія Supabase через GitHub Action безкоштовна й годиться багатьом застосункам. Робочий процес, потрібний рядок підключення та egress.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":659,"title":660,"description":661,"published":662,"category":650,"image":663,"draft":530},"\u002Fblog\u002Fdownload-your-supabase-backup","Чому ви не можете завантажити резервну копію Supabase","Завантажити резервну копію Supabase на сучасному проєкті не вийде: щоденна копія там фізична. Як це перевірити і як тримати власну копію.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":665,"title":666,"description":667,"published":662,"category":526,"image":668,"draft":530},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": бракує GRANT","З 30 жовтня нова таблиця в Supabase відповідає \"permission denied for table\", доки ви не дасте доступ. Лист показує лише половину виправлення.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":670,"title":671,"description":672,"published":673,"category":526,"image":674,"draft":530},"\u002Fblog\u002Fopen-api-endpoint-exposed","Чи є відкритий API-ендпоінт проблемою безпеки? Читайте JSON","Ваше сканування позначило відкритий API-ендпоінт. Чи це важливо, залежить від того, що повернулося, і більшість знайдених належали платформі.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":676,"title":677,"description":678,"published":679,"category":526,"image":680,"draft":530},"\u002Fblog\u002Flovable-security-scan","Сканування безпеки Lovable: чого воно не доведе","Сканування безпеки Lovable: що перевіряють Quick scan і Deep scan, коли запускається кожне, і єдине, чого не доведе жодне сканування зсередини.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":682,"title":683,"description":684,"published":685,"category":650,"image":686,"draft":530},"\u002Fblog\u002Fsupabase-backup-auth-users","Чому у вашому дампі Supabase немає користувачів","Запустіть supabase db dump окремо і отримаєте форму вашої бази та жодного її рядка, без схеми auth, у якій живуть ваші користувачі.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":688,"title":689,"description":690,"published":691,"category":526,"image":692,"draft":530},"\u002Fblog\u002Fdomain-and-certificate-expiry","Домен закінчився, сайт лежить: що буде далі","Ваш домен закінчився і сайт лежить. Ось який годинник уже пішов, чому прострочений сертифікат це менша з двох бід, і як перевірити обидва.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":694,"title":695,"description":696,"published":697,"category":526,"image":698,"draft":530},"\u002Fblog\u002Fis-lovable-safe","Чи безпечний Lovable? Що показали 18 554 застосунки Lovable","Чи безпечний Lovable? Ми прогнали 18 554 живі застосунки Lovable через дев’ять перевірок. Платформа виявилася найчистішою з п’яти. Знахідки були в застосунках.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":700,"title":701,"description":702,"published":703,"category":526,"image":704,"draft":530},"\u002Fblog\u002Fvibe-coded-app-security-checklist","Чек-лист безпеки для vibe coding, у девʼяти перевірках","Чек-лист безпеки для vibe coding із девʼяти пунктів, кожен з яких будь-хто може перевірити у вашому живому застосунку ззовні, і кожен має тест на один рядок.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":468,"title":706,"description":707,"published":708,"category":526,"image":709,"draft":530},"Секретний ключ Stripe у фронтенді може рухати гроші","Секретний ключ Stripe, відкритий у вашому фронтенді, може повертати кошти, списувати й читати кожну картку клієнта. А ключ pk_live_ там і має бути.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":218,"title":711,"description":712,"published":713,"category":526,"image":714,"draft":530},"Змінні оточення Vite відкриті: префікс означає опублікувати це","Змінні оточення Vite відкриті у вашому застосунку, бо так просив префікс. VITE_ і NEXT_PUBLIC_ означають опублікувати це, а ШІ, який їх додав, не знав ціни.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":716,"title":717,"description":718,"published":719,"category":526,"image":720,"draft":530},"\u002Fblog\u002Fbase44-source-maps","Безпека Base44: що позначає скан і що з цього виправляти вам","Безпека Base44 на 5 438 просканованих застосунках: три знахідки майже на кожному належать платформі, source map є бейджем Base44, а ваша частина коротка.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":722,"title":723,"description":724,"published":725,"category":526,"image":726,"draft":530},"\u002Fblog\u002Fis-cursor-ai-safe","Чи безпечний Cursor AI? Редактор, код і опублікований застосунок","Чи безпечний Cursor AI? Три запитання в одному пошуку: що Cursor зберігає, у чому помиляється його код і чи відкритий застосунок, який ви опублікували.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":728,"title":729,"description":730,"published":731,"category":526,"image":732,"draft":530},"\u002Fblog\u002Fis-replit-safe","Чи безпечний Replit? Що ми знайшли в 3 042 живих застосунках Replit","Чи безпечний Replit? Ми прогнали 3 042 живі застосунки Replit через дев’ять зовнішніх перевірок. Знахідки були в опублікованому застосунку, а не в хостингу.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":734,"title":735,"description":736,"published":737,"category":650,"image":738,"draft":530},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: у копії бази даних немає жодного файлу","Supabase storage backup це окрема робота. Копії бази даних зберігають список ваших файлів і жодного з них, тож після відновлення кожне завантаження зламане.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":740,"title":741,"description":742,"published":743,"category":650,"image":744,"draft":530},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery у Supabase: ціна та межі","Point-in-time recovery у Supabase відмотує базу на будь-яку секунду за останній тиждень. Коштує $100 на місяць понад Pro і покриває лише базу даних.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":746,"title":747,"description":748,"published":749,"category":650,"image":750,"draft":530},"\u002Fblog\u002Fsupabase-project-paused-recover","Проєкт Supabase на паузі? Ваші дані нікуди не зникли","Supabase поставив ваш проєкт на паузу після тижня без активності. Нічого не видалено, кнопка Restore стоїть поруч із назвою, і у вас є рік, щоб натиснути.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":752,"title":753,"description":754,"published":755,"category":526,"image":756,"draft":530},"\u002Fblog\u002Fsafest-ai-app-builder","Який білдер застосунків з ШІ найбезпечніший? 30 998 тестів","Який білдер застосунків з ШІ найбезпечніший? Ми просканували 30 998 живих застосунків з Lovable, Base44, Replit, v0 і Bolt. Оцінку вирішує не білдер.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":758,"title":759,"description":760,"published":761,"category":526,"image":762,"draft":530},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Увімкніть Row Level Security на кожній таблиці Supabase і перевірте","Row Level Security у Supabase без політики закриває таблицю повністю. Політика без увімкненого перемикача не робить нічого. Ось SQL, і ось перевірка.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":764,"title":765,"description":766,"published":767,"category":526,"image":768,"draft":530},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": чого не бачить попередження","Supabase позначає \"RLS disabled in public\" як помилку. Про політику читання, яка лишає вашу таблицю так само відкритою, він не каже нічого.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":77,"title":770,"description":771,"published":772,"category":526,"image":773,"draft":530},"Як замінити злитий ключ service_role у Supabase","Supabase каже спершу закрити витік. Інші посібники кажуть міняти негайно. Що правильно, залежить від того, куди саме потрапив ваш ключ service_role.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":775,"title":776,"description":777,"published":778,"category":526,"image":779,"draft":530},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Сканери безпеки для vibe coding у порівнянні, наш теж","Найкращий сканер безпеки для vibe coding залежить від трьох питань, на які не відповідає жоден перелік функцій. Десять інструментів і ціни.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":781,"title":782,"description":783,"published":784,"category":526,"image":785,"draft":530},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: п’ять перевірок, які зробите самі","Supabase security checker читає ваш опублікований застосунок, а не налаштування проєкту. Ось п’ять перевірок і як виконати кожну самостійно.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":787,"title":788,"description":789,"published":790,"category":526,"image":791,"draft":530},"\u002Fblog\u002Fvibe-coding-security-scanner","Сканер безпеки для vibe coding: чого не бачить скан URL","Сканер безпеки для vibe coding читає ваш робочий застосунок ззовні. Що це охоплює, чотири речі, яких він не бачить, і як читати результат.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":793,"title":794,"description":795,"published":796,"category":526,"image":797,"draft":530},"\u002Fblog\u002Fmissing-security-headers","Відсутні заголовки безпеки: коли це справді важливо","Відсутні заголовки безпеки трапляються в наших звітах найчастіше. Від чого вони захищають і коли це найменш терміновий рядок вашого звіту.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":463,"title":799,"description":800,"published":801,"category":526,"image":802,"draft":530},"Ваш ключ API OpenAI відкритий у фронтенді. Замініть його.","Ключ API OpenAI, відкритий у фронтенді, не можна прив'язати до домену. Замініть його сьогодні, перенесіть виклик на свій сервер і обмежте витрати.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":804,"title":805,"description":806,"published":807,"category":526,"image":808,"draft":530},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Ключ API у фронтенді: що насправді віддають 30 998 застосунків","Ключ API, відкритий у вашому фронтенді, зазвичай є ключем Google Maps. Ми просканували 30 998 vibe-coded застосунків і порахували, що витікає насправді.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":810,"title":811,"description":812,"published":813,"category":650,"image":814,"draft":530},"\u002Fblog\u002Fsupabase-backup-tools-compared","Інструменти резервного копіювання Supabase, і наш серед них","Чотири види інструментів резервного копіювання Supabase, що копіює кожен і коли безкоштовна GitHub Action виграє в будь-якої оплати, нашої теж.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":415,"title":816,"description":817,"published":818,"category":526,"image":819,"draft":530},"Як користуватися секретами в Replit і що все одно публікується","Як користуватися секретами в Replit: додати, прочитати і усунути дві причини undefined. А ще ключі, які цей інструмент не здатен зберегти в таємниці.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":821,"title":822,"description":823,"published":824,"category":650,"image":825,"draft":530},"\u002Fblog\u002Fback-up-supabase-free-tier","Резервні копії на безкоштовному тарифі Supabase без терміналу","На безкоштовному тарифі Supabase резервних копій немає: копію робите ви. Як зробити її з панелі та що втрачає шлях через CSV.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":827,"title":828,"description":829,"published":830,"category":526,"image":831,"draft":530},"\u002Fblog\u002Fis-supabase-secure","Чи безпечний Supabase? Так. Ваш проєкт це інше питання","Чи безпечний Supabase? Платформа проходить аудити, шифрує дані й тримає пентести. Їхня документація каже, де це закінчується і починаються ваші налаштування.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":833,"title":834,"description":835,"published":836,"category":526,"image":837,"draft":530},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Де знайти API-ключі Supabase: anon, service_role і URL","URL проєкту, ключ anon і ключ service_role лежать на одній сторінці панелі. Ось де вона, і яке з чотирьох значень має бути у вашому застосунку.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":839,"title":840,"description":841,"published":842,"category":526,"image":843,"draft":530},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy в Supabase. Що далі?","\"New row violates row-level security policy\" означає, що Supabase відмовив у записі. Швидке виправлення знову відкриває таблицю для всіх.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":845,"title":846,"description":847,"published":848,"category":526,"image":849,"draft":530},"\u002Fblog\u002Fcors-wildcard-security-risk","Чи є вайлдкард CORS ризиком для безпеки? Майже ніколи.","Чи є вайлдкард CORS ризиком для безпеки? Зазвичай це типове налаштування вашого білдера, і воно не видає нічого, що ваш сервер і так віддавав кожному.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":851,"title":852,"description":853,"published":854,"category":650,"image":855,"draft":530},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Branching у Supabase це не бекап. Він іде тільки вперед.","Чому branching у Supabase це не бекап: гілка стартує без ваших даних, а мердж переносить саму лише схему. Для чого він потрібен і що брати замість нього.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":857,"title":858,"description":859,"published":860,"category":650,"image":861,"draft":530},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Як відновити резервну копію Supabase, і що ламається потім","Як відновити резервну копію Supabase з панелі або з файлу дампа, що саме замінює відновлення і чому ваш застосунок може лишитися зламаним після нього.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":863,"title":864,"description":865,"published":866,"category":526,"image":867,"draft":530},"\u002Fblog\u002Fsupabase-storage-bucket-public","Ваш бакет Supabase Storage публічний. Чи це проблема?","Публічний бакет Supabase Storage означає, що той, хто має URL файлу, може його відкрити. Він не означає, що хтось може переглянути список вмісту.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":869,"title":870,"description":871,"published":872,"category":526,"image":873,"draft":530},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Чи є проблемою ключ API Google у вашому браузері?","Ключ API Google у відкритому коді сторінки наш сканер знаходить найчастіше, і зазвичай усе гаразд. Вирішує це одне безкоштовне налаштування.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":875,"title":876,"description":877,"published":878,"category":650,"image":879,"draft":530},"\u002Fblog\u002Fai-agent-deleted-my-database","ШІ-агент видалив мої дані в Supabase. Що можна відновити?","ШІ-агент видалив дані з вашої бази. Те, що ви зможете відновити, вирішилося раніше, а наступні хвилини вирішують, скільки з цього вціліє.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":881,"title":882,"description":883,"published":884,"category":526,"image":885,"draft":530},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Чи може будь-хто прочитати вашу базу Supabase? 3 680 застосунків","Чи може будь-хто прочитати вашу базу даних Supabase без входу? Ми просканували 30 998 живих застосунків, зроблених ШІ-білдерами, і виміряли, як часто так.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":887,"title":888,"description":889,"published":884,"category":526,"image":890,"draft":530},"\u002Fblog\u002Fsource-maps-exposed-in-production","Відкриті source maps: ваш застосунок публікує свій вихідний код","Відкрита source map дає будь-кому прочитати оригінальний код вашого застосунку, разом із коментарями. Перевірка за 30 секунд, і що важить насправді.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":343,"title":892,"description":893,"published":894,"category":526,"image":895,"draft":530},"Нові API-ключі Supabase: який із них безпечний у застосунку?","Supabase замінив anon і service_role публічними та секретними ключами. Який із них має бути у вашому застосунку, а який не має бути ніколи?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":897,"title":898,"description":899,"published":900,"category":650,"image":901,"draft":530},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","Чи робить Supabase резервні копії моєї бази? Залежить від тарифу.","Чи робить Supabase резервні копії вашої бази даних? На платних тарифах щодня, на безкоштовному жодної. Як дізнатися, що у вас насправді є.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":903,"title":904,"description":905,"published":906,"category":526,"image":907,"draft":530},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security увімкнено. Таблиця досі публічна.","Увімкнути Supabase Row Level Security не означає захистити таблицю. Захищають політики, а та, що полагодила застосунок, часто впускає всіх.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":909,"title":910,"description":911,"published":906,"category":650,"image":912,"draft":530},"\u002Fblog\u002Fversion-history-is-not-a-backup","Історія версій не є резервною копією. Вона не поверне таблицю.","Lovable і Bolt ведуть історію версій вашого коду. Ваша база даних працює як окремий сервіс, тож відкат назад не поверне ваші дані.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":914,"title":915,"description":916,"published":917,"category":650,"image":918,"draft":530},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Три способи зробити резервну копію бази Supabase, і чого бракує","Панель, pg_dump і керований сервіс. Що насправді зберігає кожен спосіб, що тихо лишає осторонь і який із них переживе втрату акаунта.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":45,"title":920,"description":921,"published":917,"category":526,"image":922,"draft":530},"Які API-ключі безпечні у браузері, а які ні","Ваш ключ anon у Supabase створений, щоб бути публічним. Ключ service_role для цього не створений, і він ігнорує всі правила, які ви задали. Як їх розрізнити.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1791705965541]