Czytałem też, że można uzyć Prepared Statements, ale jeszcze nie zagłębiałem się do tematu.
Nawet bym powiedział, że trzeba. To daje Ci pełną ochronę przed SQL injection, bo osobno wysyła do bazy zapytanie i osobno wartości, więc manipulacja zapytaniem przez wartości staje się niemożliwa.
Co z inputami, które nie trafiają do bazy danych? Najlepiej obsłużyć je wszystkie funkcją htmlspecialchars() ?
Zależy co z nimi robisz. Dane wrzucane do bazy też można przepuścić tą funkcją (lub inną podobną) jeśli nie chcesz, aby w bazie znalazł się kod możliwy do wykonania gdzieś. Czasem jest to pożądane (np. jak masz panel zarządzania postami, który ma obsłużyć HTML), a częściej raczej nie (np. jak użytkownik dodaje komentarze, które wyświetlą się na stronie i wstrzyknie tam kod, który dołączy złośliwy plik JS).
Czy osoba próbująca włamać się do serwisu jest w stanie zmodyfikować treść value option'a?
W sensie value z selecta w HTML? Oczywiście, to można zrobić inspektorem przeglądarki albo po prostu wysłać ręcznie request pod dany adres, nie korzystając wcale z Twojego formularza.
Jest jakaś reguła co obsłużyć, a co nie? Czy reguła ograniczonego zaufania podlega wszystkim inputom gdzie user ma jakiekolwiek możliwości wprowadzenia jakichś treści?
Tak, nigdy nie możesz ufać temu co przychodzi od użytkownika. Kwestia jak to sprawdzić zależy od tego, do czego potrzebujesz danych informacji.