- मोबाइल डेटिंग ऐप Feeld के बैकएंड रिव्यू में 8 कमजोरियाँ मिलीं, जिनमें प्रोफ़ाइल एक्सपोज़र, मैसेज पढ़ना/बदलना, और चैट अटैचमेंट्स तक पहुंच शामिल थी; पहली कमजोरी को छोड़कर बाकी सभी OWASP Top 10 की Broken Access Control श्रेणी में आती हैं
- सामान्य यूज़र ऐप स्क्रीन पर सीमित जानकारी ही देख पाते थे, लेकिन प्रॉक्सी से रिस्पॉन्स देखने पर ‘Like’ भेजने वाले यूज़र की उम्र, दूरी, प्रोफ़ाइल फ़ोटो और streamUserId जैसी प्रीमियम-स्तर की जानकारी मिल सकती थी
- कई कमजोरियाँ streamUserId, profileId, messageId, channelID जैसे पहचानकर्ताओं को अन्य API रिस्पॉन्स से लेकर रिक्वेस्ट पैरामीटर में डालने की तकनीक से जुड़ी थीं, जिससे दूसरे लोगों के मैसेज, मैच, प्रोफ़ाइल, लाइक्स, और चैट भेजने तक पहुंच बढ़ जाती थी
- चैट अटैचमेंट्स में सामान्य फ़ोटो, 5~15 सेकंड सीमित फ़ोटो, सामान्य वीडियो, और एक-बार चलने वाले वीडियो—सभी में समस्या पाई गई; कुछ Cloudinary और Stream CDN URL बिना authentication के एक्सेस किए जा सकते थे
- FORTBRIDGE ने 8 मार्च 2024 को Feeld को इन समस्याओं की जानकारी दी; Feeld ने कई बार प्रकाशन टालने का अनुरोध किया और 16 अगस्त 2024 को जवाब दिया कि बाकी मुद्दों को कम करने के लिए बदलाव लागू कर दिए गए हैं; ब्लॉग 10 सितंबर 2024 को प्रकाशित हुआ
Feeld में मिली कमजोरियों का दायरा
- लक्ष्य Tinder और Bumble जैसे मोबाइल डेटिंग ऐप Feeld था, जो दूरी, उम्र, जेंडर, कपल, और लोकेशन के आधार पर फ़िल्टर देता है
- प्रीमियम यूज़र kink प्रकार, threesome/group scenarios, और रुचिकर relationship type के आधार पर भी खोज सकते हैं
- सुरक्षा समीक्षा में 8 कमजोरियाँ मिलीं
- non-premium यूज़र्स को प्रोफ़ाइल जानकारी का खुलासा
- दूसरे लोगों के मैसेज पढ़ना
- चैट फ़ोटो और वीडियो अटैचमेंट्स तक बिना authentication पहुंच
- दूसरे लोगों के मैसेज delete, restore, और modify करना
- दूसरे लोगों की प्रोफ़ाइल जानकारी अपडेट करना
- किसी भी यूज़र प्रोफ़ाइल से ‘Like’ दिलवाना
- दूसरे लोगों की चैट में मैसेज भेजना
- दूसरे लोगों के मैच देखना
- पहली कमजोरी को छोड़कर बाकी सभी समस्याएँ OWASP Top 10 की Broken Access Control श्रेणी में आती हैं
non-premium यूज़र्स को दिखी प्रोफ़ाइल जानकारी
- सामान्य यूज़र जब ऐप के Likes मेनू में उन्हें Like करने वाले लोगों को देखते थे, तो केवल नाम और धुंधली फ़ोटो जैसी सीमित जानकारी दिखती थी
- Burp जैसे प्रॉक्सी टूल से रिक्वेस्ट और रिस्पॉन्स इंटरसेप्ट करने पर रिस्पॉन्स में प्रीमियम यूज़र जैसी जानकारी शामिल मिलती थी
- उम्र
- दूरी
- पूरी प्रोफ़ाइल फ़ोटो
- streamUserId
- प्रोफ़ाइल फ़ोटो
res.cloudinary.comपर स्टोर थी और बिना authentication एक्सेस की जा सकती थी - रिस्पॉन्स में मिला streamUserId आगे दूसरे लोगों के मैसेज पढ़ने वाली कमजोरी में इस्तेमाल किया जा सकता था
मैसेज और मैच access control की समस्या
- दूसरे लोगों के मैसेज पढ़ने के लिए पीड़ित का streamUserId चाहिए होता था, और यह कई API रिक्वेस्ट में उजागर हो रहा था
- उदाहरण के तौर पर
DiscoverProfilesGraphQL रिक्वेस्ट के रिस्पॉन्स से लक्ष्य यूज़र का streamUserId लेकर, चैट चैनल रिक्वेस्ट कीmembercondition में वही मान डाल दिया जाता था - रिस्पॉन्स में
"text"खोजने पर पीड़ित द्वारा भेजे और पाए गए मैसेजों की संख्या और सामग्री देखी जा सकती थी - इसी तरीके से हर मैसेज से जुड़ा messageId भी मिल जाता था, जिसका उपयोग मैसेज delete, restore, और modify करने में होता था
ChatListQueryके कमजोरprofileIdपैरामीटर को बदलने पर दूसरे यूज़र्स के मैच देखे जा सकते थे- देखी जा सकने वाली जानकारी में imaginaryName, उम्र, फ़ोटो, जेंडर, sexuality, status, और जन्मतिथि शामिल थीं
चैट अटैचमेंट्स तक बिना authentication पहुंच
- चैट में साझा किए गए अटैचमेंट्स फ़ोटो और वीडियो में बंटे थे
- फ़ोटो या तो सामान्य, बार-बार देखी जा सकने वाली फ़ोटो थीं या 5~15 सेकंड की सीमित फ़ोटो
- वीडियो या तो सामान्य चलने वाले वीडियो थे या एक-बार चलने वाले वीडियो
- सामान्य फ़ोटो Feeld ऐप से
api.cloudinary.comपर अपलोड होती थी और रिस्पॉन्स में photo_id लौटता था- इसके बाद फ़ोटो
feeld.coपर कॉपी होकर authenticated यूज़र्स को दी जाती थी cdn/chat-attachment/<receiver_profileId>/<photo_id>या<sender_profileId>/<photo_id>जैसे path इस्तेमाल होते थे- path के profileId हिस्से को कम-से-कम 1 अक्षर की किसी भी स्ट्रिंग तक घटाने पर भी authenticated यूज़र को फ़ोटो मिल जाती थी
/v1/prefix वाला path Cloudinary में स्टोर मूल फ़ोटो URL लौटाता था, और वह URL बिना authentication एक्सेस किया जा सकता था
- इसके बाद फ़ोटो
- समय-सीमित फ़ोटो अपलोड करते समय
visibilityMilliseconds:15000जैसे अतिरिक्त पैरामीटर इस्तेमाल होते थे- रिसीवर endpoint पर एक्सेस के 5~15 सेकंड बाद फ़ोटो हट जाती थी और फिर उपलब्ध नहीं रहती थी
- अपलोडर के profileId वाले endpoint से 5~15 सेकंड बाद भी authenticated यूज़र को फ़ोटो मिलती रहती थी
/v1/path Cloudinary URL लौटाता था, और वह URL बिना authentication एक्सेस किया जा सकता था
- वीडियो में, सामान्य वीडियो और एक-बार चलने वाले वीडियो दोनों के URL चैट मैसेज में शामिल थे
- सामान्य वीडियो
us-east.stream-io-cdn.comपर अपलोड होते थे - एक-बार चलने वाले वीडियो
chat.stream-io-api.comवाले अपलोड फ़्लो का उपयोग करते थे - हमलावर पहले वाली मैसेज-पढ़ने की कमजोरी से URL लेकर और
u0026को&में बदलकर बिना authentication वीडियो देख सकता था
- सामान्य वीडियो
- एक-बार चलने वाले वीडियो हमलावर के लिए दोबारा चलाए जा सकते थे, जबकि रिसीवर ऐप में एक बार देखने के बाद
video expiredदिखता था
मैसेज में छेड़छाड़, प्रोफ़ाइल बदलना, और Like की जालसाजी
chat.stream-io-api.com/messages/<messageId>endpoint पर DELETE और PUT methods के ज़रिए दूसरे लोगों के मैसेज संभाले जा सकते थे- delete किए गए मैसेज चैट में
This message was deletedके रूप में दिखते थे, लेकिन हमलावर वही DELETE रिक्वेस्ट फिर चलाकर मूल मैसेज वापस पा सकता था - हमलावर चैट का प्रतिभागी न होते हुए भी messageId के जरिए मैसेज बदल सकता था
- पीड़ित नोटिफिकेशन दबाने पर बदला हुआ मैसेज देखता था
- मैसेज के नीचे
editedदिखता था, लेकिन किसने बदला यह नहीं दिखता था - अकाउंट नाम unique नहीं थे और बदले जा सकते थे
ProfileUpdateGraphQL रिक्वेस्ट के कमजोरidपैरामीटर को पीड़ित की ID से बदलने पर नाम, sexuality, उम्र, bio जैसी प्रोफ़ाइल जानकारी अपडेट की जा सकती थीProfileLikeGraphQL रिक्वेस्ट में profile#1 से लॉगिन होने पर profile#2 से profile#3 को ‘Like’ भेजा हुआ दिखाया जा सकता था- उदाहरण में किसी भी प्रोफ़ाइल से अपनी प्रोफ़ाइल को Like भेजने के बाद, प्रीमियम अकाउंट की Likes सूची में वह Like दिखा
दूसरे लोगों की चैट में मैसेज भेजना
- हमलावर चैट का प्रतिभागी न होते हुए भी दूसरे लोगों की चैट में मैसेज भेज सकता था
- इसके लिए पहले वाली मैसेज-पढ़ने की कमजोरी से मिला channelID चाहिए होता था
channels/messaging/<channelID>/messagepath पर POST रिक्वेस्ट भेजने से उस चैनल में मैसेज जुड़ जाता था- पीड़ित को नोटिफिकेशन मिलता था और वह मैसेज देख सकता था
- सिस्टम नोटिफिकेशन को हमलावर के नाम से आया हुआ दिखाता था, लेकिन हमलावर प्रोफ़ाइल नाम बदल सकता था और नाम unique नहीं थे
सार्वजनिक टाइमलाइन
- 8 मार्च 2024 को FORTBRIDGE ने Feeld को सभी समस्याओं की जानकारी दी
- उसी दिन Feeld ने परीक्षण में इस्तेमाल हुए अकाउंट्स की जानकारी मांगी
- 2 अप्रैल 2024 को FORTBRIDGE ने अपडेट मांगा, और Feeld ने जांच जारी होने का हवाला देकर प्रकाशन रोकने को कहा
- 28 मई 2024 को Feeld ने कई fixes deploy किए और यह सत्यापित करने के लिए कि समस्याएँ हल हो गई हैं, अधिकतम 2 सप्ताह की देरी मांगी
- 8 जून 2024 को शुरुआती disclosure ईमेल के 3 महीने पूरे हुए
- 15 जुलाई 2024 को Feeld ने कहा कि कुछ समस्याओं के लिए अधिक जटिल fixes चाहिए
- 4 अगस्त 2024 को Feeld ने बाकी समस्याएँ हल होने तक प्रकाशन रोकने का अनुरोध किया
- 16 अगस्त 2024 को Feeld ने जवाब दिया कि बाकी findings को कम करने के लिए बदलाव लागू कर दिए गए हैं
- 8 सितंबर 2024 को शुरुआती disclosure के 6 महीने पूरे हुए
- 10 सितंबर 2024 को ब्लॉग प्रकाशित हुआ
- अगस्त 2025 में यह रिसर्च DEF CON 33 में प्रस्तुत की गई
1 टिप्पणियां
Hacker News पर राय
ऐसा लगता है कि permission checks सिर्फ frontend में लागू किए गए थे, और यह एक-दो endpoints तक सीमित नहीं बल्कि लगभग हर जगह ऐसा ही था
सिद्धांत रूप में यह ऐसी गलती है जिससे बचना आसान है, लेकिन मैंने ऐसी ही गलतियां इतनी बार देखी हैं कि मानने का मन नहीं करता
“सभी permissions backend पर जांचो” वाला समाधान buffer overflow के “हर जगह boundary checks लगाओ” जैसा लगता है। पूरी community जानती है कि क्या करना चाहिए, लेकिन सभी से लगातार इसे लागू करवाना आसान नहीं है
इसके विपरीत permission checks किसी खास boundary पर होते हैं और application design करने के तरीके से जुड़े होते हैं। जब भी project development के तरीके पर मेरा प्रभाव रहा, मैंने backend API development और frontend client code को साफ तौर पर अलग रखने पर जोर दिया। अनुभव से ऐसे issues से बचना और उन्हें test करना कहीं आसान हो जाता है, और developer API भी “मुफ्त में” मिल जाती है। सच कहूं तो इस approach को पसंद करने की मेरी मुख्य वजह यही है
मुझे इसका पता इसलिए चला क्योंकि lamp account के owner ने संपर्क किया कि उसका सारा data अचानक गायब हो गया है। logs देखे तो Google Bot ने internal admin screen के सभी “Delete” links click कर दिए थे। यह इसलिए संभव हुआ क्योंकि JavaScript opt-in है। मैंने developer को call करके समझाया कि उसने क्या किया था, और उस दिन web वालों पर मेरा भरोसा काफी कम हो गया
जब भी दिखता है, मैं इसे flag कर देता हूं, लेकिन client API के scope पर कभी-कभी बहुत कम सोचा जाता है, जो काफी चिंताजनक है
junior, no-code, AI code वालों को blame करना चाहूंगा, लेकिन मैं भी उनकी तरह आलसी हूं, इसलिए बस सिर हिलाकर आगे बढ़ जाता हूं
असली personal information न डालने की यह बहुत अच्छी वजह है। उदाहरण के लिए date of birth जैसी चीजें
खासकर dating apps ऐसी जानकारी मांगती लगती हैं, लेकिन ऐसा न करना बेहतर है। अपनी असली birthday से करीब एक साल इधर-उधर की value डालना बेहतर है
यह dating app बहुत mainstream नहीं है, लेकिन BDSM, group sex जैसी अलग preferences वाले लोगों और queer users को target करती है। दुनिया के कई हिस्सों में ऐसी जानकारी, कहने की जरूरत नहीं, बेहद sensitive होती है
इस हफ्ते यह अच्छी कमाई करने की वजह से media में काफी दिखी थी
https://www.theguardian.com/technology/article/2024/sep/08/t...
app की category को देखते हुए यह criminal negligence के स्तर की failure है
US और EU में jail की धमकी, data-related insurance, और data insurance की cost ही शायद एकमात्र deterrent हो सकते हैं। अगर photos ऐसी नहीं हैं जिन्हें LinkedIn पर डालना acceptable हो, तो कीमत आंखें फाड़ देने वाली होनी चाहिए
बेशक incentives छुपाने को बढ़ावा देने वाले नहीं होने चाहिए
online dating sector पूरी तरह अस्त-व्यस्त है। सिर्फ 2–3 companies हैं जिनके पास useful कहे जा सकने वाले services हैं, और वे companies evil हैं, incompetent हैं, या दोनों हैं
अब शायद open-source federated dating service जैसी किसी चीज की जरूरत है। कम से कम कुछ ऐसा जो data न बेचे, nude photos leak न करे, और लोगों को पिटने, rape होने या हत्या का शिकार होने की स्थिति में न डाले। कहना आसान है, करना नहीं
ActivityPub में Person record publish करने के जरिए इसे संभव बनाने वाला structure भी है। खासकर non-monogamous, non-heterosexual, और gender-nonconforming जरूरतों को प्राथमिकता दें तो innovation की बहुत बड़ी गुंजाइश है
लेकिन dating apps में entry सचमुच मुश्किल है। useful बनने के लिए किसी specific region में accumulated user scale चाहिए, और monetization करते ही app अनिवार्य रूप से कम useful हो जाती है। okcupid non-profit nature से हटने के बाद क्यों बिगड़ गया, इसकी वजह है
और moderation problem भी है
अगर कोई analog form को digital copy में बदलना चाहता है तो वह व्यक्ति का अधिकार है, लेकिन यह समझना चाहिए कि कोई भी system अंततः leak और distribution रोकने के लिए पर्याप्त secure नहीं है और आगे भी नहीं हो सकता
खासकर young लोग long-term में हो सकने वाले और काफी likely consequences और shame पर विचार नहीं करते। ऐसी feature देना negative outcomes को invite करने जैसा ही है
सचमुच भयानक। साफ है कि security के बारे में बिल्कुल नहीं सोचा गया
मैं game developer हूं, और यह company users को safe रखने की तुलना में हम games को fair रखने पर ज्यादा मेहनत करते हैं। इन्हें lawsuits से तबाह हो जाना चाहिए
app bugs से भरी है यह समझने से पहले ही, interests section में कोई context न होना देखकर मैं बहुत हैरान था। जैसे लगभग सभी के interests में Domination या Submission था, लेकिन वे कौन-सा role चाहते हैं, इसका कोई context नहीं था। उस scene में यह कितनी fundamentally wrong है, यह न समझना मतलब कुल मिलाकर कुछ भी न समझना है
messages और private photos अलग मामला हैं
उकसाने वाले अंदाज़ में कहें तो यह GraphQL की समस्या है
GraphQL फ्रंटएंड को डेटा query करने देता है। यह बढ़िया है, लेकिन बैकएंड के नज़रिए से यह बहुत opaque होता है, और आम तौर पर ऐसी third-party library से लागू किया जाता है जिसे access control के बारे में बिल्कुल पता नहीं होता
अगर access control को database में ही implement नहीं करने वाले हैं, तो backend code में GraphQL query को खोलकर यह पता लगाना बहुत मुश्किल है कि कौन-से records लौटाने हैं या रोकने हैं। Database में करना सबसे बुरा विकल्प नहीं है, और frontend में करने से तो निश्चित ही बेहतर है
Backend में सही access control implement करने के लिए query को समझना, database schema को समझना और ऐसे model/class/function आदि बनाने पड़ते हैं जो तय कर सकें कि “user_id XXX है तो क्या इस context में यह image देख सकता है/नहीं देख सकता।” GraphQL में इसे frontend पर implement करना कहीं आसान होता है, इसलिए उन्होंने साफ़ तौर पर वही किया होगा
मैं यह नहीं कह रहा कि GraphQL implementation अच्छा था, न ही यह कि समस्या पूरी तरह केवल GraphQL की है। मतलब यह है कि GraphQL backend को query समझने की ज़रूरत खत्म करने की कोशिश करता है, इसलिए ऐसे जटिल security scenarios को और कठिन बना देता है, और इस तरह ऐसी गलती करना आसान बना देता है
[0] उदाहरण के लिए कोई खास image user profile में public access के लिए उपलब्ध हो सकती है, लेकिन केवल matched व्यक्ति को दिखती हो, या सिर्फ chat context में दिखती हो (group chat छोड़कर), या blocked user के लिए कभी भी accessible न हो। सिर्फ इसी एक case से ढेर सारे जटिल edge cases बन सकते हैं
AST से छेड़छाड़ करने या बाकी query का context समझने की ज़रूरत नहीं है। Photo लाने वाले resolver में बस “क्या user ABC, user XYZ की photo देख सकता है?” का जवाब देना है। अगर यह inefficient हो तो कुछ data पहले से fetch कर सकते हैं या dataloader इस्तेमाल कर सकते हैं
हालांकि अगर आप GraphQL को SQL में बदलने वाली कोई जादुई library इस्तेमाल कर रहे हैं, तो बात अलग है
https://hasura.io/docs/2.0/security/allow-list/
एक सरल idea यह है कि authorization को data model में implement किया जाए। GraphQL request context के आधार पर authorization लागू कर सकने वाले resource model को
getऔरlistdelegate करे[1] https://www.apollographql.com/docs/apollo-server/security/au...
[2] https://docs.graphene-python.org/projects/django/en/latest/a...
यह हैरान करने वाली हद तक जिम्मेदार और considerate disclosure था
बहुत हैरानी की बात नहीं है। मैं इसे इस्तेमाल करता/करती हूँ, लेकिन कहूँगा/कहूँगी कि यह मेरे bank app जितना ही अयोग्य तरीके से बनाया गया है। शायद उससे भी बदतर, और यह लगभग ठीक से काम ही नहीं करता
समझ नहीं आता इसे ऐसे कैसे बनाया गया
इस app और Fetlife को देखकर लगता है कि इन communities में एक बड़ी समस्या है: quality कैसी भी हो, वे सबसे पहले आए app पर ही टिके रहते हैं
फिर कुछ समय पहले उन्होंने नया app और नया server एक साथ सभी के लिए rollout करने वाला flag day किया, और अधिकतर लोग login तक नहीं कर पाए। जो login कर पाए, अगर वे paid customers थे तो premium benefits खो बैठे, likes और chats गायब हो गए वगैरह। मैं अंत तक login नहीं कर पाया और उसी समय app छोड़ दिया
सच कहूँ तो हैरानी है कि researchers ने disclosure को इतना लंबा रोके रखा
ऐसी गंभीर privacy hole बंद करने के लिए किसी खराब startup को 6 महीने देंगे, तो वे उन informations को collect कर सकने के privilege का दुरुपयोग जारी रखेंगे। मेरे हिसाब से 2 महीने देकर disclose कर देना चाहिए। लोगों की private information के साथ पासा नहीं फेंकना चाहिए—यह उन्हें सीखना होगा
उदाहरण: https://news.ycombinator.com/item?id=41517747