Süper küreselleri doğrudan değiştirme


20

(Genellikle iyi kod yazma) doğrudan insanlar $_POSTböyle kod ile dizi değiştirmek gördüm :

// Add some value that wasn't actually posted
$_POST['last_activity'] = time();

// Alter an existing post value
$_POST['name'] = trim($_POST['name']);

// Our pretend function
// Pass the entire $_POST array as data to work with in the function
// The function update_record() will read only the values we actually need
update_record($_POST);

// ...That sure was easier than creating a new array 
//  with only the $_POST values we actually need.

update_record()$ _POST'a doğrudan erişmemesi mantıklıdır , bu nedenle örneğin diğer veri dizilerini ona aktarabiliriz, ancak elbette bu tembel, kötü tasarım veya muhtemelen yanlış mı? Ancak, hala geçerli bir dizi geçiriyoruz update_record(), neden yeni bir dizi oluşturmalıyız?

Bu sorunun konusu değil, sadece bir kullanım örneği. Ancak, birçok insanın bunun $_REQUESTverilerle yapılmaması gerektiğini söylediğini duydum ve bu kötü bir uygulama. Ama neden? Yeterince zararsız görünüyor.

Örnekler:

  • $_GETGerçekten var olmayan bir varsayılan (veya posta) değeri ayarlama

  • $_POSTForm gönderildikten sonra gerçekte gönderilmemiş değerler ekleme

  • $_GETDizi değerlerini veya anahtarları komut dosyasında çok erken bir şekilde doğrudan sterilize etme veya filtreleme (yedek sanitasyon ... neden olmasın?)

  • $_POSTBir girişi varsayılan bir değerle doldurmak için form gönderilmeden önce manuel olarak bir değer ayarlama (girdi $_POSTvarsayılan değeri için okuduğunda ; bunu yaptım)

  • Kendi $_SERVERdeğerlerinizi mi oluşturuyorsunuz? Tabii, hey neden olmasın?

  • Nasıl gibi başkaları hakkında $_COOKIEve $_SESSION? Elbette bunları doğrudan değiştirmek zorundayız değil mi? Öyleyse neden diğerleri değil?

Süper küresellerin doğrudan modifikasyonu asla yapılmamalı mı, yoksa bazı durumlarda yapılması uygun mudur?


# 1, # 2 ve # 3 ile hemfikirim çünkü beklenmedik bir kullanım (özellikle # 1 ve # 2).
Kevin Peno

İyi soru. Genel dizileri değiştirmek, genel değerleri kullanırken aynı şekilde yanlıştır. Ayrıca bu dizilerin amacı (parametreleri dışarıdan geçirerek) kod içinde karışıklık yaratmanın düz bir yoludur. Ancak, bu dizilerin bazılarının kodun başlangıcında dezenfekte edilebileceğine inanıyorum, sadece kod içinde sorunlara neden olmamak.
Tadeck

1
$ _GET veya $ _POST değişkenleri kurcalandığında ek bir uyarı yazdırmak OO giriş dizisi sarmalayıcıları (örtük filtreleme) kullanıyorum. Hala mümkündür, ancak dar durumlarla sınırlandırılmalıdır. (Modüller arası sinyalizasyon, yalnızca dağıtımcının / ön kontrol biriminin ihtiyacı olsa da.)
mario

@mario: Bu soruya bir göz atabiliyorsanız nasıl başardığınız hakkında daha fazla bilgi almak isterim: stackoverflow.com/questions/12954656
Wesley Murch

Yanıtlar:


16

PHP'nin zaten bu süper küreselleri ayarladığı göz önüne alındığında, onları değiştirmenin kötü olduğunu düşünmüyorum . Bazı durumlarda, problemleri çözmenin en iyi yolu olabilir ... özellikle kolayca değiştiremediğiniz üçüncü taraf kodlarıyla uğraşırken. ( $_GETDoğrudan kullanabilirler veya içinde bazı anahtarların var olduğunu varsayabilirler $_SERVER.)

Ancak, genel olarak konuşursak, kendi kodunuzu yazarken kötü bir uygulama olduğunu düşünüyorum. Değiştirme $_REQUESTher sayfada çalışır otomatik olasılıkla yan etkileri tanıtmak olduğunu sahneler filtrenin arkasında bazı verileri. ("Sihirli tırnak" kanıt için neden tüm sorunları görün.)

Dolayısıyla, bunu yapmayacaksanız (süper küreselleri otomatik olarak filtreleyin), aşağıdakiler size herhangi bir fayda sağlamaz:

$_POST['foo'] = filter($_POST['foo']);

kolayca yapabileceğiniz zaman:

$foo = filter($_POST['foo']);

Ben o site genelindeki ayrım yapmak çok daha açık olduğunu düşünüyorum $_POSTve $_GETedilir hep , güvenilmeyen verileri filtresiz ve onlar gerektiğini asla olduğu gibi kullanılabilir.

Filtrelenmiş değeri başka bir değişkene kopyalayarak, "Ne yaptığımı anlıyorum ... Bu girdiyi filtreledim ve kullanımı güvenli" iddiasında bulunuyorsunuz.


Giriş için teşekkürler, internetim yaklaşık 2 gündür bu yüzden kimseye cevap verme şansım olmadı. Örnekte, $ _POST'u değiştirdim ve bir güncelleme işlevine geçmek için bir veri dizisi olarak kullandım, bu işlevde okuyacağımız birkaç $ _POST anahtarı olduğunu varsayalım. Yeni bir dizi oluşturmak için tercih ediyorum ama insanlar bunun yerine bunu gördük, bu yüzden hala "kötü kod" olarak adlandırılıp adlandırılmayacağından emin değilim, ama en azından bu şekilde yaslanmış olduğunu düşünüyorum. Sanırım bunu yapmak için ihtiyaç duyduğunuz her an, daha iyi bir yol var.
Wesley Murch

1
@Wesley, "kötü" olmasının başlıca nedeni, bazı kullanıcı verilerini sterilize etmeyi unutacağınızdır. Örneğinizde, bir anahtarı değiştirip tüm diziyi geçirirsiniz. Bu verilerden bazıları işlenmeyen kötü amaçlı girdi içeriyorsa ne olur? Bu yeni diziyi elle oluşturmak, sadece ihtiyaç duyduğunuz şeyleri $_POSTiçine kopyalamak , ilerlerken dezenfekte etmek çok daha iyidir . Ve bunu yapan diğer insanlarla ilgili olarak ... pek çok insan çok kötü PHP kodu yazıyor, ama bu sizin için de bir mazeret değil. :)
konforce

Bence sadece verileri sterilize etmenin yanı sıra, diğer küresel kürtaj istismar uygulamalarını da vurgulamalıydım. Muhtemelen tamamen dışarıda bırakmış ve daha net bir soru yazmalıydım, insanlar özellikle güvenlik yönlerini ele almaktan ve geri kalanını görmezden gelmekten hoşlanırlar. Nankör görünmemek için, gerçekten geri bildirimi takdir ediyorum. Bir gün bekleyeceğim ve bu onay işaretini vereceğim, çünkü bazı iyi noktaları ele aldınız, ancak sorunun yeni olduğu 3 dakika boyunca oylama partisini kaçırdınız :) Tekrar teşekkürler!
Wesley Murch

9

Genel olarak, önceden tanımlanmış süper küreselleri değiştirmemenizi öneririm, böylece sterilize edilmiş verilerin ve ham / güvenilir olmayan verilerin ne olduğu açıktır.

Diğerleri, talep döngüsünün başlangıcında süper küreselleri temizlerseniz, başka bir yerde onlar hakkında endişelenmenize gerek olmadığını önerebilir.

İhtiyacınız olduğunda her zaman onları eşleştirirdim:

$id = (int)$_POST['id'];

veya benzeri.

Diğer değişkenler açısından bu herhangi birine yazmayın iyi bir uygulamadır $_GET, $_POST, $_REQUEST, $_SERVERveya $_COOKIE. $_SESSIONancak farklıdır çünkü oturuma genellikle daha sonra oturumdaki farklı istekler arasında kalıcı olarak veri yazmak istersiniz.


2
Bu tür küresellerin ortadan kalkmasının daha fazla nedeni, gerektiğinde onları almak için çağrılabilecek nesneler / yöntemler ile değiştirildi. Neden setcookievar, ama çerezleri alıyoruz $_COOKIE? Ayrıca, $_COOKIEyalnızca geçerli oturum başlatıldığında ayarlandığından ve hiçbir zaman güncelleştirilmediğinden, kodun sonraki bölümlerinin güncel bilgilere sahip olması için her iki alandaki çerezleri değiştirmenizi / ayarlamanızı gerektirir.
Kevin Peno

Teşekkürler James, bir süredir çevrimdışı olduğum için cevap veremedim. Uzun bir hikaye kısaca anlatmak gerekirse - Sana katılıyorum. Her zaman post / get / etc'ye yazmaktan daha iyi bir çözüm var, ancak " bunu asla asla yapma " da olduğu gibi kesinlikle kötü bir fikir olarak kabul edilip edilmediğinden hala emin değilim . Yani, bu tür bir kodla tekrar karşılaşırsam, özensiz kodda "onları çağırmak" hakkım olduğunu düşünüyor musunuz, yoksa bu bazen akıllı ve güvenli bir şekilde kullanılabilir mi?
Wesley Murch

@Wesley "Asla bunu asla yapma" olsaydı, süper küreseller muhtemelen kesinlikle salt okunur olurdu - değiller. Bunları uygulama kodunuzda belirtmek veya üzerine yazmak kötü bir uygulama olarak adlandırılırdım.
Michel Feldheim

3

Bundan kaçınmalısınız. Belki bir süre bir şeyi sterilize etmeyi unuttun, o zaman tehlikeli verileri alabilirsin. Dezenfekte ederken verileri yeni bir yapıya kopyalarsanız

  • Sadece ne istiyorsun / neye ihtiyacın var, ne $_POSTde değil
  • Yeni oluşturulan dizide bazı anahtarlar yoksa veya hiç eksikse, muhtemelen bir hata alırsınız

Diğer diğer komut dosyaları, diziye dokunulmadığını ve meraklı tepki gösterebileceğini varsayabilir.


2

Süper küresel değiştirme fikrini hiç sevmedim çünkü yanıltıcı. Neredeyse daha iyi bir yol olacak bir şey yapmak için hızlı bir hacky yoludur.

$_POSTÖrneğin değerini değiştirirseniz, yazılımın vermediği verileri aldığını söylüyorsunuz.

GERÇEK SORUN

Bunun büyük bir sorun haline geldiği gerçek bir yaşam durumu var:

Bir ekipte çalıştığınızı düşünün. İdeal bir dünyada herkes aynı sözdizimini kullanır, ancak ideal bir dünyada yaşamıyoruz. Bir geliştirici, John, yayınlanan verilere erişmeyi sever $_POST. Yazıdaki bir şeyi değiştirir:

$_POST['ranking'] = 2; // John has changed ranking from 1 to 2 for whatever reason

Daha sonra filter_input, kullanıcının kurcalayabileceği verileri işlerken yazılımı korumak için girilen (yani GET, POST, SERVER, COOKIE) verilerine erişmek için kullanmayı tercih eden başka bir geliştirici olan Chris var. Yazılım kısmında, post değerini alması gerekiyor ranking. Kodun parçası John'un SONRA .

$ranking = filter_input(INPUT_POST, 'ranking', FILTER_SANITIZE_NUMBER_INT);
// $ranking = 1

Yukarıdaki örnekte, bir küresel küreyi değiştirerek PHP'yi kırdınız. John her $_POST['ranking']ne sebeple olursa olsun değerini 2 olarak belirlemiştir, ancak şimdi Chris 1 değerini almıştır

Bunu yapmanın başka bir yolunu görmediğimde:

AWS yük dengeleyicisinin arkasında wordpress'i blog olarak kullanan bir proje üzerinde çalıştım. Bu, değerini değiştirir $_SERVER['remote_address']. Bu durumda, diğer geliştiricinin aşağıdakileri yapmaktan başka seçeneği yoktu:

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $parts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    $_SERVER['REMOTE_ADDR'] = $parts[0];
}

Sonuç

Süper küreselleri değiştirmekten neredeyse kesinlikle daha iyi bir yol var


1

Bence buradaki asıl soru “temayı neden değiştirmelisiniz?”. Bunun için geçerli bir neden göremiyorum. Bir imput'u sterilize etmeniz gerekiyorsa, yerel bir değişken kullanmak isteyebilirsiniz ...

Kod yeterince kısa değilse (örneğin, 50 satırdan daha kısa), bu süper-global modifikasyonu değiştirmek, kodunuzu yalnızca bakımını ve altını çizmeyi zorlaştıracaktır.

Bu arada, işleve $ _POST iletmeniz gerekmez, çünkü bir işlevin yerel kapsamı içinde bile erişilebilen süper küresel bir dizidir.


3
Ama o olmalıdır geçmek. Başka test etmek çok zor ve herhangi bir (daha çirkin) kesmek olmadan işlevi / yöntemi diğer değerlerle çağırmak mümkün değil
KingCrunch

Peki, yönteminin ne yaptığına bağlı. Yalnızca $ _POST dizisinde ne varsa ayrıştırmak için tasarlanmışsa, onu geçirmesi gerekmez. Tabii ki, daha genel / soyut bir amaca hizmet ediyorsa, haklı olduğunuzdan daha fazla.

2
@Thomas, burada King ile hemfikirim. Küresel olsalar bile, diğer kapsamlarda küresel bir şey kullanmamalısınız çünkü sıkı bağlantıya neden olur (bu nedenle işlev tekrar kullanılamaz). Örneğiniz göz önüne alındığında, işlev verileri sterilize etmekse, neden sadece $_POSTverileri sterilize ediyor ? İçeri aktarma $_POSTişlevi herhangi bir veriyi sterilize eder .
Kevin Peno

0

Süper küreselleri değiştirmek için hiçbir neden olmaması gerektiğini söyleyerek bu soruyu ilk olarak cevapladıktan sonra, bu cevabı karar verdiğim bir zaman örneğiyle düzenliyorum.

Şu anda bir requestsütun yeniden yazmak veritabanı tablo üzerinde sütun karşılık gelen targetsütuna kullanıcı yönlendirir üzerinde çalışıyorum .

Örneğin, bir requestolabilir blog/title-hereve targetolabilir blog.php?id=1.

Yana blog.phpbekliyor $_GETdeğişkenleri ve ben değiştirmek istemiyorum header("Location:")böyle yaptığımı sol kulüpler şey:

$uri    = explode('?', $uri_request)[0];
$params = explode('?', $uri_request)[1];
parse_str($params, $_GET);

Bu sütun $_GETtarafından iletilen istenen parametreleri içeren bir dizi oluşturur target.

Sonuçta, kesinlikle gerekmedikçe süper küreselleri değiştirmeye karşı şiddetle tavsiye ediyorum .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.