I have an Apache server which hosts a public website and an internal website. However, since Apache denotes virtual hosts based on the
Host HTTP header, couldn't someone on the Internet request my server's IP with the
Host header set to its internal name/IP?
Yes, that's possible. In fact, if the internal name is in (global) DNS, they can request the internal site by name.
However, you can still do what you're trying to do and be (mostly) secure. You don't say what version of Apache you're running, and things changed slightly for version 2.3. In Apache 2.3 or 2.4, you can use
mod_authz_host to restrict the internal server to specific IP addresses, namely those on your internal network. So, you could do something like this:
Require ip 10.1 Require ip 10.2 172.20 192.168.2
Depending on the complexity of the local network, one
Require ip may be enough. The full documentation is here: http://httpd.apache.org/docs/current/mod/mod_authz_host.html
For versions prior to Apache 2.3, you would use
mod_access (http://www.auburn.edu/docs/apache/mod/mod_access.html) which works slightly differently but can accomplish the same thing.
You are still running the external and internal sites on the same instance of Apache, so an error in Apache itself could potentially expose internal pages to the outside. So could errors in setting up the access controls or errors in placing files. Access via VPN will present an address from the VPN concentrator, so those will look like 'internal' requests, which is probably good. Finally, requests from a proxy server will present the address of the proxy. That probably doesn't apply; there's a note in the apache docs about this.
You can increase security somewhat by using a server with two network interfaces and assigning each virtual host to its own interface. You'd use an internal (RFC 1918) IP address to the internal virtual server. For best security, you need two physical machines, one on the internal network, with an internal address, and one in the DMZ with a registered (or port-forwarded) address.
Finally, you could require authentication (login) for the internal server. Whether this is practical or necessary. depends upon the number of people who will be using the internal server and how sensitive it is.
I'm going to assume that the internal reference means the applications user base, not that the server sits on the same network as you could bind the website to the internal IP in that case.
As previously mentioned the "internal" hostname can be discovered through DNS (fairly common), but also through brute force (public tools exists) or apache misconfiguration where the internal hostname is also the default host or leaks in an error page.
Authentication is a simple way to prevent unauthorized access to a virtual host that has to be accessible via an external IP.