Sandbox

Sandbox, şablonlarda hangi etiketlerin, PHP fonksiyonlarının, metotların vb. kullanılabileceği üzerinde size denetim veren bir güvenlik katmanı sağlar. Sandbox modu sayesinde, uygulamayı tehlikeye atmaktan ya da istenmeyen işlemler yapılmasından endişe etmeden bir müşteriyle veya dış bir kodlayıcıyla şablon oluşturmada güvenle iş birliği yapabilirsiniz.

Nasıl çalışır? Şablonda neye izin vermek istediğimizi basitçe tanımlarız. Başlangıçta her şey yasaktır ve izinleri kademeli olarak veririz. Aşağıdaki kod, şablon yazarının {block}, {if}, {else} ve {=} etiketlerini (sonuncusu bir değişkeni veya ifadeyi yazdırmaya yarayan etikettir) ve tüm filtreleri kullanmasına izin verir:

$policy = new Latte\Sandbox\SecurityPolicy;
$policy->allowTags(['block', 'if', 'else', '=']);
$policy->allowFilters($policy::All);

$latte->setPolicy($policy);

Tek tek genel fonksiyonlara, metotlara veya nesne özelliklerine de erişim izni verebiliriz:

$policy->allowFunctions(['trim', 'strlen']);
$policy->allowMethods(Nette\Security\User::class, ['isLoggedIn', 'isAllowed']);
$policy->allowProperties(Nette\Database\Row::class, $policy::All);

allowMethods() ve allowProperties() ile verilen izinler, verilen sınıfın alt sınıflarının örnekleri için de geçerlidir (denetim is_a() kullanır).

Harika değil mi? Her şeyi çok düşük bir düzeyde denetleyebilirsiniz. Şablon, izin verilmeyen bir fonksiyonu çağırmayı ya da izin verilmeyen bir metoda veya özelliğe erişmeyi denerse, bir Latte\SecurityViolationException fırlatır.

Güvenli varsayılan politika

Her şeyin yasak olduğu bir politikayı sıfırdan oluşturmak kullanışlı olmayabilir, bu yüzden güvenli bir temelden başlayabilirsiniz:

$policy = Latte\Sandbox\SecurityPolicy::createSafePolicy();

Bu güvenli temel şu anlama gelir: contentType, debugbreak, dump, extends, import, include, layout, php, sandbox, snippet, snippetArea, templatePrint, varPrint, embed dışındaki tüm standart etiketlere izin verilir. datastream, noescape ve nocheck dışındaki tüm standart filtrelere izin verilir. Son olarak $iterator nesnesinin metotlarına ve özelliklerine erişime izin verilir.

Sandbox'ı etkinleştirme

Kurallar, {sandbox} etiketiyle eklediğimiz şablon için geçerlidir. Bu bir bakıma {include}'a benzer: sandbox modunu açar ve {include} gibi çevredeki değişkenleri otomatik aktarmaz. Ancak onları açıkça aktarabilirsiniz, örneğin {sandbox 'untrusted.latte', a: 1, b: 2}:

{sandbox 'untrusted.latte'}

Böylece layout ve tek tek sayfalar tüm etiketleri ve değişkenleri serbestçe kullanabilir; kısıtlamalar yalnızca untrusted.latte şablonuna uygulanır.

Yasak bir etiketin veya filtrenin kullanılması gibi bazı ihlaller derleme zamanında saptanır. Bir nesnenin izin verilmeyen metotlarının çağrılması gibi başkaları çalışma zamanında saptanır. Şablon başka hatalar da içerebilir. Sandbox'lanmış şablondan gelen bir istisnanın tüm render sürecini bozmasını önlemek için, örneğin onu yalnızca günlükleyen kendi istisna işleyicinizi tanımlayabilirsiniz.

Sandbox modunu doğrudan tüm şablonlar için etkinleştirmek istersek, bu kolaydır:

$latte->setSandboxMode();

Üretilen kodun denetimi

Bir kullanıcının sayfaya sözdizimsel olarak doğru ama yasak olan ve PHP Compile Error'a yol açan PHP kodu eklememesini sağlamak için, şablonların PHP linter tarafından denetlenmesini öneririz. Bu işlevselliği Engine::enablePhpLinter() metoduyla etkinleştirebilirsiniz. Denetim için PHP ikili dosyasını çağırması gerektiğinden, yolunu parametre olarak verin:

$latte = new Latte\Engine;
$latte->enablePhpLinter('/path/to/php');

Sandbox'ın korumadıkları

İzin verdiğiniz etiketlerin, fonksiyonların, metotların ve özelliklerin ötesinde, sandbox politikadan bağımsız olarak birkaç yapıyı koşulsuz yasaklar: new operatörü, $this değişkeni, değişken değişkenler ($$var) ve |noescape filtresi.

Sandbox, açık işlemleri güvenilir biçimde korur: fonksiyon, metot ve filtre çağrılarını, ayrıca nesne özelliklerine erişimi. Ancak denetimlerinin ulaşamadığı bir şey var ve onu bilmekte yarar var.

Bir nesneyi yazdırdığınızda veya onu herhangi bir dize bağlamında kullandığınızda, PHP otomatik olarak onun sihirli __toString() metodunu çağırır. Politika bu örtük dönüşümü denetlemez, bu yüzden __toString() metodu izin verilenler arasında olmasa bile çalışır. Şablon yazarı böylece, şablonda ulaşabildiği herhangi bir nesnede __toString()'i tetikleyebilir. Bu, sandbox'ın engellediği açık {$obj->__toString()} biçiminden farklıdır:

{$obj}              {* __toString() çağırır *}
{$obj . '!'}        {* aynısı (birleştirme) *}
{="price: $obj"}    {* aynısı (dize enterpolasyonu) *}
{$obj|upper}        {* aynısı (bir filtre üzerinden) *}

__toString()'in amacı nesnenin metin gösterimini üretmektir, bu yüzden ulaşılabilir olması genellikle zarar vermez. Sorun ancak __toString()'in yan etkileri varsa (örneğin veritabanına yazmak veya sorgu yapmak) ya da hassas veri döndürüyorsa doğar.

Latte bu en doğrudan durumları yakalayabilirdi, ama hepsinde güvenilir biçimde değil. Bir nesneyi dizeye dönüştürmek bir metot çağrısı değil, bir ifadenin içinde birçok yerde ortaya çıkan yerleşik bir dil işlemidir. Bunların bazılarında (örneğin bir nesneyi bir dizeyle karşılaştırırken ya da çağrılan bir fonksiyonun veya filtrenin içinde), meşru kullanımı da engellemeden güvenilir biçimde araya girilemezdi. Bu yüzden __toString()'in ulaşılabilir olduğunu hesaba katmanız gerekir.

__toString()'i yan etkileri olan veya hassas veri açığa çıkaran nesneleri sandbox'a maruz bırakmayın. Bu yalnızca şablona doğrudan aktardığınız nesneler için değil, yazarın izin verilen bir fonksiyonun, metodun veya özelliğin dönüş değeri olarak elde ettiği nesneler için de geçerlidir.

versiyon: 3.x